// AudioSink.cpp: implementation of the AudioSink class. // ////////////////////////////////////////////////////////////////////// #include #include "AudioSink.h" #include "AudioSource.h" #include "AudioSample.h" using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// AudioSink::AudioSink() { bSinkRunning = false; bSinkThreadRunning = false; sinkThreadHandle = NULL; sinkThreadID = 0; sinkThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL); sinkThreadStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL); InitializeCriticalSection(&audioSourcesMutex); InitializeCriticalSection(&sinkThreadMutex); InitializeCriticalSection(&sinkStateMutex); InitializeCriticalSection(&sinkStartStopMutex); } AudioSink::~AudioSink() { CloseHandle(sinkThreadStartEvent); CloseHandle(sinkThreadStopEvent); DeleteCriticalSection(&audioSourcesMutex); DeleteCriticalSection(&sinkThreadMutex); DeleteCriticalSection(&sinkStateMutex); DeleteCriticalSection(&sinkStartStopMutex); } int AudioSink::SubscribeAudioSource(AudioSource *audioSource) { EnterCriticalSection(&audioSourcesMutex); if (find(audioSources.begin(), audioSources.end(), audioSource) == audioSources.end()) { audioSources.push_back(audioSource); } LeaveCriticalSection(&audioSourcesMutex); return 0; } int AudioSink::UnsubscribeAudioSource(AudioSource *audioSource) { EnterCriticalSection(&audioSourcesMutex); vector::iterator position = NULL; position = find(audioSources.begin(), audioSources.end(), audioSource); if (position != audioSources.end()) { audioSources.erase(position); } LeaveCriticalSection(&audioSourcesMutex); return 0; } int AudioSink::RenderAudioSamples(std::vector > &data) { tracer.tracef(ERR, "RenderAudioSamples : ERROR : pure virtual function call !!!\n"); return 0; } int AudioSink::TakeNextAudioSample(AudioSample *audioSample, AudioSource *audioSource) { int result(0); inputData.clear(); if (audioSample) { audioSample->AddRef(this); // we later release it inputData.push_back(make_pair(audioSample, audioSource)); } EnterCriticalSection(&audioSourcesMutex); vector::iterator iter = audioSources.begin(); for (iter=audioSources.begin(); iter!=audioSources.end(); iter++) { if (*iter == audioSource) { continue; } AudioSample *pAudioSample = NULL; // tracer.tracef(DET, "TakeNextAudioSample : calling GiveNextAudioSample\n"); result = (*iter)->GiveNextAudioSample(&pAudioSample, this); if (result != 0) { tracer.tracef(ERR, "TakeNextAudioSample : GiveNextAudioSample from %s returned error %d\n", (*iter)->TraceName(), result); if (pAudioSample) { pAudioSample->Release(this); pAudioSample = NULL; } } else { if (pAudioSample) { inputData.push_back(make_pair(pAudioSample, *iter)); } } } LeaveCriticalSection(&audioSourcesMutex); result = RenderAudioSamples(inputData); for (int i=0; iRelease(this); sample = NULL; } } return result; } int AudioSink::StartSink() { int result(0); SetTraceLevel(); EnterCriticalSection(&sinkStateMutex); if (bSinkThreadRunning || bSinkRunning) { result = -10; tracer.tracef(ERR, "StartSink : bSinkRunning = %d, bSinkThreadRunning = %d\n", bSinkRunning, bSinkThreadRunning); } else { result = SinkStarted(); if (result != 0) { tracer.tracef(ERR, "StartSink : SinkStarted returned %d\n", result); result = -20; } else { bSinkRunning = true; } } LeaveCriticalSection(&sinkStateMutex); return result; } int AudioSink::StopSink() { int result(0); EnterCriticalSection(&sinkStateMutex); if (bSinkThreadRunning) { result = -10; tracer.tracef(ERR, "StopSink : bSinkThreadRunning = %d\n", bSinkThreadRunning); } else { if (bSinkRunning) { result = SinkStopped(); if (result != 0) { tracer.tracef(ERR, "StartSink : SinkStarted returned %d\n", result); result = -20; } else { bSinkRunning = false; } } else { tracer.tracef(SIG, "StopSink : bSinkRunning = false\n"); } } LeaveCriticalSection(&sinkStateMutex); return result; } int AudioSink::StartSinkThread() { int result(0); int returnCode(0); tracer.tracef(EE, "StartSinkThread\n"); SetTraceLevel(); EnterCriticalSection(&sinkStateMutex); tracer.tracef(ARB, "StartSinkThread : entered sinkStateMutex\n"); do { if (bSinkRunning || bSinkThreadRunning) { tracer.tracef(ERR, "StartSinkThread : e-error : bSinkRunning = %d, bSinkThreadRunning = %d\n", bSinkRunning, bSinkThreadRunning); result = -10; break; } if (sinkThreadHandle != NULL || sinkThreadID != 0) { tracer.tracef(ERR, "StartSinkThread : e-error : sinkThreadHandle = 0x%x, sinkThreadID = 0x%x\n", sinkThreadHandle, sinkThreadID); result = -20; break; } ResetEvent(sinkThreadStartEvent); ResetEvent(sinkThreadStopEvent); bSinkThreadShouldStop = true; // we make it false only if everything else succeeds sinkThreadHandle = CreateThread(NULL, 0, SinkThreadProc, (void *)this, CREATE_SUSPENDED, &sinkThreadID); if (sinkThreadHandle == NULL) { sinkThreadID = 0; tracer.tracef(ERR, "StartSinkThread : e-CreateThread\n"); result = -30; break; } returnCode = SinkThreadStarted(sinkThreadHandle, sinkThreadID); if (returnCode != 0) { tracer.tracef(ERR, "StartSinkThread : e-SinkThreadStarted : %d 0x%x\n", returnCode, returnCode); result = -40; } if (result == 0) // this ensures that if SinkThreadStarted failed, then we stop the thread { bSinkThreadShouldStop = false; } returnCode = ResumeThread(sinkThreadHandle); if (result == -1) { TerminateThread(sinkThreadHandle, 0); sinkThreadHandle = NULL; sinkThreadID = 0; tracer.tracef(ERR, "StartSinkThread : e-ResumeThread : %d 0x%x\n", returnCode, returnCode); result = -50; break; } WaitForSingleObject(sinkThreadStartEvent, INFINITE); } while (false); LeaveCriticalSection(&sinkStateMutex); tracer.tracef(ARB, "StartSinkThread : left sinkStateMutex\n"); tracer.tracef(EE, "~StartSinkThread : returning %d\n", result); return result; } int AudioSink::StopSinkThread() { int result(0); int returnCode(0); bool waitForThread = true; tracer.tracef(EE, "StopSinkThread\n"); EnterCriticalSection(&sinkStartStopMutex); tracer.tracef(ARB, "StopSinkThread : entered sinkStartStopMutex\n"); EnterCriticalSection(&sinkStateMutex); tracer.tracef(ARB, "StopSinkThread : entered sinkStateMutex\n"); do { if (!bSinkThreadRunning) { tracer.tracef(SIG, "StopSinkThread : bSinkThreadRunning = false\n"); result = 0; waitForThread = false; break; } bSinkThreadShouldStop = true; } while (false); LeaveCriticalSection(&sinkStateMutex); tracer.tracef(ARB, "StopSinkThread : left sinkStateMutex\n"); if (waitForThread) { tracer.tracef(ARB, "StopSinkThread : before WaitForSingleObject\n"); WaitForSingleObject(sinkThreadStopEvent, INFINITE); } LeaveCriticalSection(&sinkStartStopMutex); tracer.tracef(ARB, "StopSinkThread : left sinkStartStopMutex\n"); tracer.tracef(EE, "~StopSinkThread : returning %d\n", result); return result; } DWORD WINAPI AudioSink::SinkThreadProc(LPVOID params) { int result(0); int returnCode(0); AudioSink *audioSink = (AudioSink *)params; Tracer &tracer = audioSink->tracer; tracer.tracef(EE, "SinkThreadProc : begin\n"); audioSink->bSinkThreadRunning = true; tracer.tracef(ARB, "SinkThreadProc : setting sinkThreadStartEvent\n"); SetEvent(audioSink->sinkThreadStartEvent); while (!audioSink->bSinkThreadShouldStop) { (audioSink->inputData).clear(); tracer.tracef(DET, "SinkThreadProc : Entering audioSourcesMutex\n"); EnterCriticalSection(&(audioSink->audioSourcesMutex)); vector::iterator iter = (audioSink->audioSources).begin(); for (iter = (audioSink->audioSources).begin(); iter != (audioSink->audioSources).end(); iter++) { AudioSample *pAudioSample = NULL; returnCode = (*iter)->GiveNextAudioSample(&pAudioSample, audioSink); if (returnCode != 0) { if (pAudioSample) { pAudioSample->Release(audioSink); pAudioSample = NULL; } } else { if (pAudioSample) { (audioSink->inputData).push_back(make_pair(pAudioSample, *iter)); } } } LeaveCriticalSection(&(audioSink->audioSourcesMutex)); tracer.tracef(DET, "SinkThreadProc : Left audioSourcesMutex\n"); tracer.tracef(DET, "SinkThreadProc : Rendering audioSamples\n"); returnCode = audioSink->RenderAudioSamples(audioSink->inputData); for (int i=0; i<(audioSink->inputData).size(); i++) { AudioSample *sample = (audioSink->inputData[i]).first; if (sample) { sample->Release(audioSink); sample = NULL; } } } tracer.tracef(ARB, "SinkThreadProc : broke out of while loop\n"); tracer.tracef(EE, "SinkThreadProc : entering sinkStateMutex\n"); EnterCriticalSection(&(audioSink->sinkStateMutex)); audioSink->bSinkThreadRunning = false; tracer.tracef(ARB, "SinkThreadProc : calling SinkThreadStopped\n"); audioSink->SinkThreadStopped(audioSink->sinkThreadHandle, audioSink->sinkThreadID); CloseHandle(audioSink->sinkThreadHandle); audioSink->sinkThreadHandle = NULL; audioSink->sinkThreadID = 0; LeaveCriticalSection(&(audioSink->sinkStateMutex)); tracer.tracef(EE, "SinkThreadProc : left sinkStateMutex\n"); tracer.tracef(ARB, "SinkThreadProc : setting sinkThreadStopEvent and exiting\n"); BOOL setResult = SetEvent(audioSink->sinkThreadStopEvent); return result; } int AudioSink::SinkThreadStarted(HANDLE sinkThreadHandle, DWORD sinkThreadID) { return 0; } int AudioSink::SinkThreadStopped(HANDLE sinkThreadHandle, DWORD sinkThreadID) { return 0; } int AudioSink::SinkStarted() { return 0; } int AudioSink::SinkStopped() { return 0; }