// WaveAudioSink.cpp: implementation of the WaveAudioSink class. // ////////////////////////////////////////////////////////////////////// #include "AudioSample.h" #include "AudioSource.h" #include "WaveAudioSink.h" using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// WaveAudioSink::WaveAudioSink() { char subFacilityName[100]; sprintf(subFacilityName, "WaveAudioSink:%x", this); tracer.SetSubFacilityName(subFacilityName); SetTraceLevel(); tracer.tracef(EE, "Constructor begin\n"); enabled = true; waveoutDeviceID = WAVE_MAPPER; frameSize = WAVESINK_DEFAULT_WAVEHDR_SIZE; numFrames = WAVESINK_NUM_WAVEHDR; InitializeCriticalSection(&dataMutex); InitializeCriticalSection(&freeBuffersMutex); InitializeCriticalSection(&filterMutex); dataEvent = CreateEvent(NULL, FALSE, FALSE, NULL); pauseEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // set default format wfx.nAvgBytesPerSec = 16000; wfx.wFormatTag = WAVE_FORMAT_PCM; wfx.wBitsPerSample = 16; wfx.nChannels = 1; wfx.nBlockAlign = 2; wfx.nSamplesPerSec = 8000; wfx.cbSize = 0; tracer.tracef(EE, "Constructor end\n"); } WaveAudioSink::~WaveAudioSink() { tracer.tracef(EE, "Destructor begin\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveAudioSink~ : entered filterMutex\n"); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveAudioSink~ : left filterMutex\n"); DeleteCriticalSection(&dataMutex); DeleteCriticalSection(&freeBuffersMutex); DeleteCriticalSection(&filterMutex); CloseHandle(dataEvent); CloseHandle(pauseEvent); tracer.tracef(EE, "Destructor end\n"); } int WaveAudioSink::SetTraceLevel() { long SystemMask = 0; if ((SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "AllComponents", 0x0)) == 0) { SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "WaveAudioSink", 0x100000); } tracer.SetSystemMask(SystemMask); return 0; } int WaveAudioSink::SetVolume(unsigned long volume) { tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetVolume %d\n", volume); volume = min(100, volume); unsigned long normalizedVolume = (volume * 0xffff) / 100; unsigned long volumeToSet = (normalizedVolume << 16) + normalizedVolume; tracer.tracef(SDI_LEVEL_DETAILED, "SetVolume : Entering dataMutex\n"); EnterCriticalSection(&dataMutex); if (bRunning) { tracer.tracef(SDI_LEVEL_ARBITRARY, "SetVolume : waveOutSetVolume\n"); MMRESULT mr = waveOutSetVolume(hWaveOut, volumeToSet); tracer.tracef(SDI_LEVEL_ARBITRARY, "SetVolume : ~waveOutSetVolume\n"); LeaveCriticalSection(&dataMutex); tracer.tracef(SDI_LEVEL_DETAILED, "SetVolume : Left dataMutex\n"); if (FAILED(mr)) { tracer.tracef(SDI_LEVEL_ERROR, "SetVolume : e-waveOutSetVolume : 0x%x\n", mr); } } else { LeaveCriticalSection(&dataMutex); tracer.tracef(SDI_LEVEL_DETAILED, "SetVolume : Left dataMutex\n"); } tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetVolume\n"); return NOERROR; } int WaveAudioSink::SetFrameSize(unsigned long size) { tracer.tracef(EE, "SetFrameSize %u\n", size); frameSize = min(size, WAVESINK_MAX_WAVEHDR_SIZE); tracer.tracef(EE, "~SetFrameSize\n"); return NOERROR; } int WaveAudioSink::SetNumFrames(unsigned long num) { tracer.tracef(EE, "SetNumFrames %u\n", num); numFrames = min(num, WAVESINK_MAX_WAVEHDR); tracer.tracef(EE, "~SetNumFrames\n"); return NOERROR; } int WaveAudioSink::BeginAudioRender() { tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "BeginAudioRender\n"); HRESULT result = NOERROR; tracer.tracef(SDI_LEVEL_DETAILED, "BeginAudioRender : Entering freeBuffersMutex\n"); EnterCriticalSection(&freeBuffersMutex); freeBuffers.clear(); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(SDI_LEVEL_DETAILED, "BeginAudioRender : Left freeBuffersMutex\n"); MMRESULT mr = NOERROR; WaveFormat::TraceFormat(&tracer, ARB, wfx); tracer.tracef(SDI_LEVEL_ARBITRARY, "BeginAudioRender : waveOutOpen\n"); mr = waveOutOpen(&hWaveOut, waveoutDeviceID, &wfx, (DWORD)SpeakerCallback, DWORD(this), CALLBACK_FUNCTION); tracer.tracef(SDI_LEVEL_ARBITRARY, "BeginAudioRender : ~waveOutOpen\n"); if (mr != NOERROR) { tracer.tracef(SDI_LEVEL_ERROR, "BeginAudioRender : e-waveOutOpen : 0x%x\n", mr); WaveFormat::TraceFormat(&tracer, ERR, wfx); Sleep(1000); tracer.tracef(SDI_LEVEL_ERROR, "BeginAudioRender : waveOutOpen : 2nd try\n"); mr = waveOutOpen(&hWaveOut, waveoutDeviceID, &wfx, (DWORD)SpeakerCallback, DWORD(this), CALLBACK_FUNCTION); tracer.tracef(SDI_LEVEL_ERROR, "BeginAudioRender : ~waveOutOpen : returned 0x%x\n", mr); if (mr != NOERROR) { tracer.tracef(SDI_LEVEL_ERROR, "BeginAudioRender : e-waveOutOpen : 0x%x\n", mr); WaveFormat::TraceFormat(&tracer, ERR, wfx); result = -10; } } if (result == 0) { for (int i=0; i 0) { tracer.tracef(SDI_LEVEL_DETAILED, "GetBuffer : bufferLength > 0\n"); wHdr = freeBuffers.front(); freeBuffers.pop_front(); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GetBuffer : Left freeBuffersMutex\n"); break; } else { tracer.tracef(SDI_LEVEL_DETAILED, "GetBuffer : bufferLength <= 0\n"); ResetEvent(dataEvent); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GetBuffer : Left freeBuffersMutex - waiting for dataEvent (1000 ms)\n"); WaitForSingleObject(dataEvent, 1000); } } tracer.tracef(DET, "~GetBuffer\n"); return wHdr; } void CALLBACK WaveAudioSink::SpeakerCallback(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { WAVEHDR *wHdr; WaveAudioSink *filter = (WaveAudioSink *)dwInstance; // (filter->tracer).tracef(SDI_LEVEL_ENTRY_EXIT, "SpeakerCallback\n"); switch(uMsg) { case WOM_OPEN: // (filter->tracer).tracef(SDI_LEVEL_ARBITRARY, "SpeakerCallback : WOM_OPEN\n"); break; case WOM_CLOSE: // (filter->tracer).tracef(SDI_LEVEL_ARBITRARY, "SpeakerCallback : WOM_CLOSE\n"); SetEvent(filter->dataEvent); break; case WOM_DONE: (filter->tracer).tracef(SDI_LEVEL_DETAILED, "SpeakerCallback : WOM_DONE\n"); wHdr = (WAVEHDR *)dwParam1; (filter->tracer).tracef(SDI_LEVEL_DETAILED, "SpeakerCallback : Entering freeBuffersMutex\n"); EnterCriticalSection(&(filter->freeBuffersMutex)); (filter->freeBuffers).push_back(wHdr); SetEvent(filter->dataEvent); // we do this within the critsec because getbuffer resets this within the same critsec LeaveCriticalSection(&(filter->freeBuffersMutex)); (filter->tracer).tracef(SDI_LEVEL_DETAILED, "SpeakerCallback : Left freeBuffersMutex\n"); break; default: break; } // (filter->tracer).tracef(SDI_LEVEL_ENTRY_EXIT, "~SpeakerCallback\n"); } int WaveAudioSink::SinkStarted() { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkStarted\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkStarted : entered filterMutex\n"); do { if (bRunning) { tracer.tracef(ERR, "SinkStarted : e-error : already running\n"); result = -10; break; } returnCode = BeginAudioRender(); if (returnCode != 0) { tracer.tracef(ERR, "SinkStarted : e-BeginAudioRender : %d 0x%x\n", returnCode, returnCode); result = -20; break; } bRunning = true; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkStarted : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkStarted : returning %d\n", result); return result; } int WaveAudioSink::SinkStopped() { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkStopped\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkStopped : entered filterMutex\n"); do { if (!bRunning) { tracer.tracef(ERR, "SinkStopped : e-error : not running\n"); result = -10; break; } returnCode = EndAudioRender(); if (returnCode != 0) { tracer.tracef(ERR, "SinkStopped : e-EndAudioRender : %d 0x%x\n", returnCode, returnCode); result = -20; break; } bRunning = false; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkStopped : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkStopped : returning %d\n", result); return result; } int WaveAudioSink::SinkThreadStarted(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); SetTraceLevel(); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkThreadStarted\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkThreadStarted : entered filterMutex\n"); do { returnCode = SetThreadPriority(sinkThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); if (returnCode == 0) { returnCode = GetLastError(); tracer.tracef(ERR, "SinkThreadStarted : e-SetThreadPriority : %d 0x%x\n", returnCode, returnCode); } returnCode = BeginAudioRender(); if (returnCode != 0) { tracer.tracef(ERR, "SinkThreadStarted : e-BeginAudioRender : %d 0x%x\n", returnCode, returnCode); result = -10; break; } bRunning = true; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkThreadStarted : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkThreadStarted : returning %d\n", result); return result; } int WaveAudioSink::SinkThreadStopped(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SinkThreadStopped\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkThreadStopped : entered filterMutex\n"); do { if (!bRunning) { tracer.tracef(ERR, "SinkThreadStopped : not running\n"); result = -10; break; } returnCode = EndAudioRender(); if (returnCode != 0) { tracer.tracef(ERR, "SinkThreadStopped : e-EndAudioRender : %d 0x%x\n", returnCode, returnCode); result = -20; break; } bRunning = false; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SinkThreadStopped : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SinkThreadStopped : returning %d\n", result); return result; } int WaveAudioSink::SetDeviceID(unsigned int deviceID) { waveoutDeviceID = deviceID; return 0; } unsigned int WaveAudioSink::GetDeviceID() { return (unsigned int)waveoutDeviceID; } int WaveAudioSink::SetFormat(int waveFormatNumber) { tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SetFormat %d\n", waveFormatNumber); wfx = WaveFormat::GetWaveFormat(waveFormatNumber); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SetFormat\n"); return 0; } int WaveAudioSink::RenderAudioSamples(std::vector > &data) { tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples\n"); HRESULT result = NOERROR; AudioSample *sample = NULL; if (data.size() > 0) { sample = data[0].first; } else { Sleep(5); } if (sample) { WAVEHDR *wHdr = GetBuffer(); if (!wHdr) { Sleep(5); result = -10; } else { int bytesToPlay; if (sample->DataSize() > 0) { bytesToPlay = min(frameSize, sample->DataSize()); tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : memcpy(0x%x, 0x%x, %d)\n", wHdr->lpData, sample->Data(), bytesToPlay); memcpy(wHdr->lpData, sample->Data(), bytesToPlay); } else { bytesToPlay = min(frameSize, sample->SilenceSize()); tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : memset(0x%x, 0, %d)\n", wHdr->lpData, bytesToPlay); memset(wHdr->lpData, 0, bytesToPlay); } wHdr->dwBufferLength = bytesToPlay; tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : Entering dataMutex\n"); EnterCriticalSection(&dataMutex); tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : waveOutWrite\n"); MMRESULT mmr = waveOutWrite(hWaveOut, wHdr, sizeof(*wHdr)); tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : ~waveOutWrite\n"); LeaveCriticalSection(&dataMutex); tracer.tracef(SDI_LEVEL_DETAILED, "RenderAudioSamples : Left dataMutex\n"); } } tracer.tracef(SDI_LEVEL_DETAILED, "~RenderAudioSamples\n"); return result; }