Output plug-ins must implement and export the functions defined in output_plug.h. There are different interface versions. It is recommended to use level 3.
The initialization interface does not need to be thread safe.
ULONG DLLENTRY output_init (void** a)
ULONG DLLENTRY output_uninit(void* a)
The output_init function is called when the user requests
the use of your output
plug-in. So only one output plug-in is active at any given time. It
should initialize the control variables for an eventual call to output_command
with OUTPUT_OPEN.
output_uninit
is called when another output
plug-in is request by the user and should free the allocated memory for
a.
The control interface does not need to be thread safe itself, but it is called from a different thread than the data interface.
ULONG DLLENTRY output_command(void* a, ULONG msg, OUTPUT_PARAMS2* info)
OUTPUT_OPEN opens the device or file needed for
output.OUTPUT_CLOSE immediately stop playback and close
the audio device. OUTPUT_VOLUME changes the volume of an output
device. OUTPUT_PAUSE pauses the playback (ie.: block in output_request_buffer()).
OUTPUT_SETUP setup the format that output_request_buffer()
will most likely receive, event callback. OUTPUT_TRASH_BUFFERS trash any buffers currently
awaiting to be played. There is a lot of commands to implement for this function. Parameters needed for each of them are described in the definition of the OUTPUT_PARAMS2 structure in the output_plug.h file.
The status graph is as follows:
OUTPUT_VOLUMEOUTPUT_SETUPOUTPUT_OPEN - now we are active. The data interface may be used.OUTPUT_CLOSE - now we are no longer active.The function codes (OUTPUT_PAUSE and OUTPUT_TRASH_BUFFERS)
are allowed only in active mode. OUTPUT_VOLUME is always
allowed.
output_event
with the parameter OUTEVENT_PLAY_ERROR
when a playback error occurs. This will stop the playback, but it is
not guaranteed that this ist done immediately.output_event with OUTEVENT_END_OF_DATA
when the last sample is really processed. This must not be done unless
the function output_play_samples has been called with a
buffer pointer of NULL (flush signal).OUTEVENT_LOW_WATER
and OUTEVENT_HIGH_WATER to signal that
the buffers are running low or the buffers are getting full
respectively. This is used by PM123 to control the scheduling priority.OUTPUT_OPEN call uses the
following syntax:OUTPUT_OPEN
call. You may ignore this.The data interface is only used when the control interface is in activated state.
The data interface does not need to be thread safe itself, but it is called from a different thread than the control interface.
The level 3 interface allocates the sample buffers by the plug-in
rather than the data source. This is known to cause less double
buffering. The buffer size is no longer fixed. The functions output_request_buffer
and output_commit_buffer have to be called alternatingly.
Anything else is an error.
All samples are passed as 16 bit signed integers regardless what type the input has been.
int DLLENTRY output_request_buffer(void* a, FORMAT_INFO2* format, float** buf)
NULL indicates that
there are no more samples to come (flush signal). sizeof(float). Return values
≤ 0 signals a fatal error, except for the flush signal
which
always returns zero. This function is called by the decoder or last in chain filter plug-in to store samples for playing. The function call may block until enough buffer space is available.
After a flush request (buf == NULL)
there is
no need to call output_commit_buffer. The flush signal
should be used to play any internal buffers regardless if they are
completely full or not.
Note that the flush signal is an implicit request for an OUTEVENT_END_OF_DATA
event. The output_request_buffer call must not block
until all buffers are played.
void DLLENTRY output_commit_buffer(void* a, int len, PM123_TIME pos)
output_request_buffer.
This does not mean that it is a good advise to play a buffer smaller
than usual unless you receive a flush signal. A length of 0 is not an
error but an undo request to the previous output_request_buffer
call. output_playing_pos.
This is a time index of the starting point of this buffer in seconds.
The time position marker may have a large offset far
beyond the length of the current file. This function is called by the decoder or last in chain filter plug-in to play the stored samples.
The status interface must be thread safe and reentrant.
PM123_TIME DLLENTRY output_playing_pos(void* a)This function returns the pos from the buffer that the user currently hears. The return value is a time index in seconds. The plug-in may use its knowledge to calculate the time with higher resolution than one buffer. But you must not make any assumptions about the zero point.
BOOL DLLENTRY output_playing_data(void* a)Returns TRUE if the output plug-in still has some buffers to play.
ULONG DLLENTRY output_playing_samples(void* a, FORMAT_INFO2* info, float* buf, int len)
This function is used by visual plug-ins so the user can visualize what is currently being played. len is usually in the order of 2048 samples or less. So check that amount usually required by your visual plug-ins before making complicated buffering functions in your output plug-in.
This interface revisions should not be used for development because
the impementations tends to modify the current thread's priority to
boost the speed of the data source. This implies that the current
thread while calling output_play_samples is the
bottleneck and that it is always the same thread. Both is not true in
general (e.g. remote data sources).
See level 3 interface. This part of the interface has not been changed.
The control interface does not need to be thread safe itself, but it is called from a different thread than the data interface.
ULONG DLLENTRY output_command(void *a, ULONG msg, OUTPUT_PARAMS *info)
OUTPUT_OPEN opens the device or file needed for
output. OUTPUT_CLOSE closes it. OUTPUT_VOLUME changes the volume of an output
device. OUTPUT_PAUSE pauses the playback (ie.: block in
output_playsamples()). OUTPUT_SETUP setup the format that
output_playsamples() will most likely
receive, boost priority values, error_display functions and hwnd. OUTPUT_TRASH_BUFFERS trash any buffers currently
awating to be played. OUTPUT_NOBUFFERMODE forces the plug-in to not
accumulate buffers for the time being.There is a lot of commands to implement for this function. Parameters needed for each of them are described in the definition of the structure in the .h file.
The status graph is as follows:
OUTPUT_VOLUMEOUTPUT_SETUPOUTPUT_OPEN - now we are active. The data interface may be used.OUTPUT_OPEN - next songOUTPUT_CLOSE - now we are no longer active.The other function codes (OUTPUT_PAUSE and OUTPUT_TRASH_BUFFERS)
are allowed only in active mode. OUTPUT_VOLUME is always
allowed.
The output plug-in MUST WinPostMsg() the following messages to hwnd:
WM_PLAYERROR when a playback error occures. WM_OUTPUT_OUTOFDATA when the output plug-in has
finished playing all.
its buffers. Not needed when always_hungry flag is
enabled. The data interface is only used when the control interface is in activated state.
The data interface does not need to be thread safe itself, but it is called from a different thread than the control interface.
int DLLENTRY output_play_samples(void* a, FORMAT_INFO* format, char* buf, int len, int posmarker)
WAVE_FORMAT_PCM
and from PM123 version 1.40 the number of bits per sample is always 16.
The number of channels may change during playback but not within a
buffer. output_playing_pos.
This function is called by the decoder or last in chain filter plug-in to play samples.
The status interface must be thread safe and reentrant.
int DLLENTRY output_playing_pos(void* a)This function returns the posmarker from the buffer that the user currently hears. The return value is a time index in milliseconds. The plug-in may use this knowledge to calculate time indices with higher resolution than one buffer. But you must not make any assumptions about the zero point.
BOOL DLLENTRY output_playing_data(void* a)Returns TRUE if the output plug-in still has some buffers to play.
ULONG DLLENTRY output_playing_samples(void* a, FORMAT_INFO* info, char* buf, int len)
This function is used by visual plug-ins so the user can visualize what is currently being played. len is usually in the order of 2048 samples or less. So check that amount usually required by your visual plug-ins before making complicated buffering functions in your output plug-in.