123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- /** (c) Nullsoft, Inc. C O N F I D E N T I A L
- ** Filename:
- ** Project:
- ** Description:
- ** Author: Ben Allison [email protected]
- ** Created:
- **/
- #include "main.h"
- #include "OutputPluginAudioStream.h"
- #include "out.h"
- #include "api.h"
- #include "WinampAttributes.h"
- int m_converting = 0;
- static volatile int streamsInUse = 0;
- static void * volatile streamBuffer = 0;
- static volatile size_t streamCanWrite = 0;
- static volatile HANDLE streamWait = 0;
- static volatile HANDLE streamGo = 0;
- static volatile HANDLE streamKill = 0;
- static volatile bool streamPlaying = false;
- static volatile AudioParameters *streamParameters = 0;
- static In_Module * volatile streamIn = 0;
- static volatile int opens = 0;
- void ConvertEOF()
- {
- streamPlaying = false;
- //if (--opens==0)
- SetEvent(streamWait);
- }
- static int StreamOpen(int samplerate, int numchannels, int bitspersamp, int bufferlenms, int prebufferms)
- {
- streamParameters->bitsPerSample = bitspersamp;
- streamParameters->channels = numchannels;
- streamParameters->sampleRate = samplerate;
- streamParameters->sizeBytes = (size_t) - 1;
- // we will try to use GetFileInfo to get a length
- int lengthMS;
- InW_GetFileInfo(streamIn, 0, 0, &lengthMS);
- if (lengthMS > 0)
- {
- streamParameters->sizeBytes = MulDiv(lengthMS, numchannels * bitspersamp * samplerate, 8000);
- }
- streamPlaying = true;
- return 0;
- }
- static void StreamClose()
- {
- streamPlaying = false;
- // SetEvent(streamWait);
- }
- static int StreamWrite(char *buf, int len)
- {
- again:
- // null buffer means EOF
- if (buf == NULL)
- {
- streamPlaying = false;
- //SetEvent(streamWait);
- return 0;
- }
- if (streamCanWrite == 0)
- {
- //Sleep(10); // input plugin isn't checking StreamCanWrite() properly, so we'll sleep for them
- //return 1;
- }
- // copy into user-supplied buffer
- int toCopy = min((int)streamCanWrite, len);
- memcpy(streamBuffer, buf, toCopy);
- streamCanWrite -= toCopy;
- streamBuffer = ((char *)streamBuffer) + toCopy;
- // the input plugin may have given us too much data, so we'll have to check that
- // increment the user's stuff
- len -= toCopy;
- buf += toCopy;
- if (len) // len>0 implies streamCanWrite == 0
- {
- ResetEvent(streamGo);
- SetEvent(streamWait);
- /* benski> this Sleep() code causes a major slowdown,
- probably because of high thread priorities in some plugins
- while (streamCanWrite == 0)
- Sleep(100);
- */
- HANDLE events[2] = {streamKill, streamGo};
- switch (WaitForMultipleObjects(2, events, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0 + 1:
- goto again;
- default:
- return 0;
- }
- }
- // signal event to let ReadAudio() return, if the buffer is full
- if (streamCanWrite == 0)
- SetEvent(streamWait);
- return 0;
- }
- static int StreamCanWrite()
- {
- if (streamCanWrite)
- return 65536;
- else
- return 0;
- }
- static int StreamIsPlaying()
- {
- return 0;
- }
- static void StreamSet(int nothing)
- {}
- static int StreamGetOutputTime()
- {
- return 0;
- }
- static int StreamGetWrittenTime()
- {
- return 0;
- }
- static Out_Module streamOut =
- {
- OUT_VER,
- "dummy output",
- 14000,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- StreamOpen,
- StreamClose,
- StreamWrite,
- StreamCanWrite,
- StreamIsPlaying,
- NULL, //pause
- StreamSet, //setvolume
- StreamSet, //setpan
- StreamSet, //flush
- StreamGetOutputTime,
- StreamGetWrittenTime,
- };
- OutputPluginAudioStream::OutputPluginAudioStream()
- {
- oldBits=config_audio_bits;
- oldSurround=config_audio_surround;
- oldMono=config_audio_mono;
- oldRG=config_replaygain;
- }
- bool OutputPluginAudioStream::Open(In_Module *in, const wchar_t *filename, AudioParameters *parameters)
- {
- // set some globals, since winamp output plugins don't have user data/context pointers
- opens++;
- m_converting = 1;
- // this will ask the input plugin to produce our output format (not a guarantee, though)
- config_audio_bits = parameters->bitsPerSample;
- config_audio_surround = (parameters->channels > 2);
- config_audio_mono = (parameters->channels == 1);
- config_replaygain=false;
- streamWait = CreateEvent(NULL, FALSE, FALSE, NULL);
- streamGo = CreateEvent(NULL, FALSE, FALSE, NULL);
- streamKill = CreateEvent(NULL, TRUE, FALSE, NULL);
- streamCanWrite = 0;
- streamBuffer = 0;
- streamPlaying = false;
- streamParameters = parameters;
- streamIn = in;
- in->outMod = &streamOut;
- int ret = InW_Play(in, filename);
- if (ret)
- {
- parameters->errorCode = API_DECODEFILE_FAILURE;
- opens--;
- return false;
- }
- if (in->UsesOutputPlug&IN_MODULE_FLAG_USES_OUTPUT_PLUGIN)
- {
- int cnt = 5000;
- while (!streamPlaying && cnt > 0)
- {
- MSG msg;
- if (PeekMessage(&msg, NULL, 0, 0, FALSE))
- WASABI_API_APP->app_messageLoopStep();
- else
- {
- Sleep(1);
- cnt--;
- }
- }
- }
- else
- {
- parameters->errorCode = API_DECODEFILE_NO_INTERFACE;
- opens--;
- return false;
- }
- if (!streamPlaying)
- {
- parameters->errorCode = API_DECODEFILE_FAILURE;
- opens--;
- return false;
- }
- return true;
- }
- size_t OutputPluginAudioStream::ReadAudio(void *buffer, size_t sizeBytes)
- {
- streamBuffer = buffer;
- streamCanWrite = sizeBytes;
- SetEvent(streamGo);
- HANDLE events[2] = {streamKill, streamWait};
- switch (WaitForMultipleObjects(2, events, FALSE, INFINITE))
- {
- case WAIT_OBJECT_0 + 1: // streamWait, which gets triggered when buffer is full or output is done
- return sizeBytes - streamCanWrite; // streamCanWrite will be >0 if there was a partial write, e.g. on EOF
- default:
- return 0; // no point
- }
- return sizeBytes - streamCanWrite;
- }
- OutputPluginAudioStream::~OutputPluginAudioStream()
- {
- SetEvent(streamKill);
- streamIn->Stop();
- DeleteObject(streamWait);
- DeleteObject(streamGo);
- DeleteObject(streamKill);
- streamWait = 0;
- config_audio_bits = oldBits;
- config_audio_surround = oldSurround;
- config_audio_mono=oldMono;
- config_replaygain=oldRG;
- }
- #define CBCLASS OutputPluginAudioStream
- START_DISPATCH;
- CB(IFC_AUDIOSTREAM_READAUDIO, ReadAudio)
- END_DISPATCH;
|