diff options
Diffstat (limited to 'Src/Winamp/OutputPluginAudioStream.cpp')
-rw-r--r-- | Src/Winamp/OutputPluginAudioStream.cpp | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/Src/Winamp/OutputPluginAudioStream.cpp b/Src/Winamp/OutputPluginAudioStream.cpp new file mode 100644 index 00000000..f724aad1 --- /dev/null +++ b/Src/Winamp/OutputPluginAudioStream.cpp @@ -0,0 +1,270 @@ +/** (c) Nullsoft, Inc. C O N F I D E N T I A L + ** Filename: + ** Project: + ** Description: + ** Author: Ben Allison benski@nullsoft.com + ** 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; |