This doesn't have all the includes you'd need, but it shows the output plugin interface (IMJOutputPlugin). You'll have to export a C++ class (interface) from a DLL with a function GetOutputPlugin.
Here's the main header file:
/************************************************************************************
IMJOutputPlugin - base class for Media Jukebox output plugins.
Copyright (c) 2001-2008 JRiver, Inc.
It's strongly recommend that you DO NOT ALTER this file. This class is a base building
class for new plugins. Add any specific changes to the new class.
Last updated: January 2, 2003
************************************************************************************/
/************************************************************************************
Description of architecture:
1) Open(...) with some desired output format
2) The plugin gets run in a loop like this, until the user stops playback or there's no more data:
UpdateBuffer(...)
remove any spent (played) data from your buffer and return the number of bytes removed
FillBuffers(...)
fill your buffer(s) with as much data as possible, return the number of bytes added or
FILL_BUFFERS_NO_ROOM if they're already full (so returning 0 would mean that there was no more data available to fill from)
Sleep(...)
the loop will pause GetSleepMS(...) milliseconds (1000 = 1 second)... if you have large buffers, you can make this
a higher number to prevent FillBuffers(...) from getting called too often
notes:
- It is crucial that the number of bytes returned by UpdateBuffer(...) and FillBuffers(...) stay synchronized. For every byte that
gets added, another byte must be eventually removed. Otherwise Media Jukebox's internal buffers will get confused and fill up.
- Keep in mind that some amount of time passes between UpdateBuffer(...) and FillBuffers(...), so be careful when tracking
whether a buffer has been processed and should be added to the "played bytes" returned by UpdateBuffer(...).
- A loop is used instead of events to ease the creation of plugins -- that way, systems like DirectSound don't
require a polling thread inside of the plugin (their callback methods are unreliable, so can't be used)
- With functions that return an int, 0 means success, and any other value is considered an error code.
************************************************************************************/
#pragma once
/************************************************************************************
Output plugins MUST be built in Unicode
************************************************************************************/
#if (!defined(UNICODE) || !defined(_UNICODE))
#error "Output plugins must be built in Unicode mode!"
#endif
/************************************************************************************
Includes
************************************************************************************/
#include <windows.h>
#include "AudioFormat.h"
/************************************************************************************
Definitions
************************************************************************************/
#define FILL_BUFFERS_NO_ROOM (-1000)
/************************************************************************************
Information fields
************************************************************************************/
enum MJ_OUTPUT_PLUGIN_INFO_FIELDS
{
MJ_OUTPUT_PLUGIN_INFO_NAME, // get the display name of the plugin (i.e. "JRiver WaveOut" or similar)
MJ_OUTPUT_PLUGIN_INFO_SUPPORTED_BY_SYSTEM, // return TRUE if the plugin is supported by the system
MJ_OUTPUT_PLUGIN_INFO_SUPPORTS_USER_BIT_DEPTH, // whether or not this plugin can support user bit depth selections
MJ_OUTPUT_PLUGIN_INFO_ACCELERATED_SPEED, // return TRUE for plugins that run as fast as possible (instead of real-time) (Disk Writer, etc.)
MJ_OUTPUT_PLUGIN_INFO_HAS_CONFIGURATION, // whether or not the plugin supports MJ_OUTPUT_PLUGIN_COMMAND_CONFIGURE
MJ_OUTPUT_PLUGIN_INFO_AUTHORIZATION, // get the authorization code
MJ_OUTPUT_PLUGIN_INFO_ZONE, // the playback zone (so settings can be saved on a zone-by-zone basis)
MJ_OUTPUT_PLUGIN_INFO_NO_PRE_BUFFER, // return TRUE for plugins that run real-time in background (where choppy playback isn't an issue) but require quick response to cancel
MJ_OUTPUT_PLUGIN_INFO_OUTPUT_DEVICE_NAME, // the name of the current sound card line (empty if default or unknown)
MJ_OUTPUT_PLUGIN_INFO_CUSTOM_BASE = 1000, // some derived classes need custom messages
};
/************************************************************************************
Commands
************************************************************************************/
enum MJ_OUTPUT_PLUGIN_COMMANDS // description [nParam1, nParam2]
{
MJ_OUTPUT_PLUGIN_COMMAND_PAUSE, // set the pause state [pause state (non-zero for paused), ignored]
MJ_OUTPUT_PLUGIN_COMMAND_FLUSH, // flush (used when seeking, etc. to remove queued data) [ignored, ignored]
MJ_OUTPUT_PLUGIN_COMMAND_SET_EOF, // called to signal that the EOF has been reached (can be used to break files with Disk Writer, etc.) [bytes until EOF, ignored]
MJ_OUTPUT_PLUGIN_COMMAND_FINALIZE, // the EOF has been reached, and more data isn't on the way (at least for a while) [ignored, ignored]
MJ_OUTPUT_PLUGIN_COMMAND_CONFIGURE, // show the plugin configuration dialog [HWND parent, ignored]
};
/************************************************************************************
Security modes
************************************************************************************/
#ifndef MJ_OUTPUT_PLUGIN_SECURITY_MODE_NONE_DEFINED
#define MJ_OUTPUT_PLUGIN_SECURITY_MODE_NONE_DEFINED
static const GUID MJ_OUTPUT_PLUGIN_SECURITY_MODE_NONE = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
#endif
/*************************************************************************************
Callbacks (used by the output plugin)
*************************************************************************************/
class IMJOutputPluginCallbacks
{
public:
// get data for playback (already DSP'd, cross-faded, etc.)
// note, you can specify a nBitsPerSample if MJ_OUTPUT_PLUGIN_INFO_SUPPORTS_USER_BIT_DEPTH is false
// also, setting bAllowEatCrossFade to false will make it so you'll get guaranteed fade lengths (good for disk writing, etc.)
virtual int FillPlaybackBuffer(void * pBuffer, int nMaximumBytes, int nBitsPerSample = -1, BOOL bAllowEatCrossFade = TRUE) = 0;
// gets the number of milliseconds that are empty in the buffer
// use this to slow down to real-time using GetSleepMS(...) for accelerated outputs
// otherwise, cross-fading, etc. won't work
// example: GetSleepMS(IMJOutputPluginCallbacks * pCallbacks) { return (pCallbacks->GetBufferEmptyMS() > 4000) ? 1000 : 10; }
virtual int GetBufferEmptyMS() = 0;
};
/*************************************************************************************
The output plugin base class
*************************************************************************************/
class IMJOutputPlugin
{
public:
// construction / destruction
IMJOutputPlugin() {}
virtual ~IMJOutputPlugin() {}
// open the plugin
virtual int Open(const CAudioFormat * pafOutput) = 0;
// main processing loop functions -- see the above architecture description
virtual int UpdateBuffer() = 0;
virtual int FillBuffers(IMJOutputPluginCallbacks * pCallbacks) = 0;
virtual int GetSleepMS(IMJOutputPluginCallbacks * pCallbacks) = 0;
// generic interface functions (see enumerations for details)
virtual int GetInformation(MJ_OUTPUT_PLUGIN_INFO_FIELDS nInfoID, LPTSTR pResult = NULL) = 0;
virtual int SetInformation(MJ_OUTPUT_PLUGIN_INFO_FIELDS nInfoID, LPCTSTR pValue) = 0;
virtual int DoCommand(MJ_OUTPUT_PLUGIN_COMMANDS nCommandID, int nParam1 = 0, int nParam2 = 0) = 0;
};
/*************************************************************************************
External functions that the plugin will export
*************************************************************************************/
typedef int (*proc_GetOutputPlugin)(int nIndex, IMJOutputPlugin ** ppPlugin);
Hopefully this is enough to get started.