Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
270
Src/Winamp/OutputPluginAudioStream.cpp
Normal file
270
Src/Winamp/OutputPluginAudioStream.cpp
Normal file
|
@ -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;
|
Loading…
Add table
Add a link
Reference in a new issue