// AudioSource.cpp: implementation of the AudioSource class. // ////////////////////////////////////////////////////////////////////// #include #include #include "AudioSource.h" #include "AudioSink.h" #include "AudioSample.h" using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// AudioSource::AudioSource() { bSourceRunning = false; bSourceThreadRunning = false; bSourceThreadShouldStop = true; sourceThreadHandle = NULL; sourceThreadID = 0; sourceThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL); sourceThreadStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL); InitializeCriticalSection(&audioSinksMutex); InitializeCriticalSection(&sourceThreadMutex); InitializeCriticalSection(&sourceStateMutex); InitializeCriticalSection(&sourceStartStopMutex); } AudioSource::~AudioSource() { CloseHandle(sourceThreadStartEvent); CloseHandle(sourceThreadStopEvent); DeleteCriticalSection(&audioSinksMutex); DeleteCriticalSection(&sourceThreadMutex); DeleteCriticalSection(&sourceStateMutex); DeleteCriticalSection(&sourceStartStopMutex); } int AudioSource::SubscribeAudioSink(AudioSink *audioSink) { EnterCriticalSection(&audioSinksMutex); if (find(audioSinks.begin(), audioSinks.end(), audioSink) == audioSinks.end()) { audioSinks.push_back(audioSink); } LeaveCriticalSection(&audioSinksMutex); return 0; } int AudioSource::UnsubscribeAudioSink(AudioSink *audioSink) { EnterCriticalSection(&audioSinksMutex); vector::iterator position = NULL; position = find(audioSinks.begin(), audioSinks.end(), audioSink); if (position != audioSinks.end()) { audioSinks.erase(position); } LeaveCriticalSection(&audioSinksMutex); return 0; } int AudioSource::StartSource() { int result(0); SetTraceLevel(); EnterCriticalSection(&sourceStateMutex); if (bSourceThreadRunning || bSourceRunning) { result = -10; tracer.tracef(ERR, "StartSource : bSourceThreadRunning = %d, bSourceRunning = %d\n", bSourceThreadRunning, bSourceRunning); } else { result = SourceStarted(); if (result != 0) { tracer.tracef(ERR, "StartSource : SourceStarted returned error %d\n", result); result = -20; } else { bSourceRunning = true; } } LeaveCriticalSection(&sourceStateMutex); return result; } int AudioSource::StopSource() { int result(0); EnterCriticalSection(&sourceStateMutex); if (bSourceThreadRunning) { result = -10; } else { result = SourceStopped(); if (result != 0) { tracer.tracef(ERR, "StopSource : SourceStopped returned error %d\n", result); result = -20; } bSourceRunning = false; } LeaveCriticalSection(&sourceStateMutex); return result; } int AudioSource::StartSourceThread() { tracer.tracef(EE, "StartSourceThread\n"); int result(0); SetTraceLevel(); tracer.tracef(ARB, "StartSourceThread : entering sourceStateMutex\n"); EnterCriticalSection(&sourceStateMutex); do { if (bSourceRunning || bSourceThreadRunning) { tracer.tracef(ERR, "StartSourceThread : e-error : bSourceRunning = %d, bSourceThreadRunning = %d\n", bSourceRunning, bSourceThreadRunning); result = -10; break; } if (sourceThreadHandle != NULL || sourceThreadID != 0) { tracer.tracef(ERR, "StartSourceThread : e-error : sourceThreadHandle = 0x%x, sourceThreadID = 0x%x\n", sourceThreadHandle, sourceThreadID); result = -20; break; } BOOL resetResult; tracer.tracef(ARB, "StartSourceThread : resetting sourceThreadStartEvent and sourceThreadStopEvent\n"); resetResult = ResetEvent(sourceThreadStartEvent); if (resetResult == 0) { tracer.tracef(ERR, "StartSourceThread : e-ResetEvent(sourceThreadStartedEvent) : 0x%x\n", GetLastError()); } resetResult = ResetEvent(sourceThreadStopEvent); if (resetResult == 0) { tracer.tracef(ERR, "StartSourceThread : e-ResetEvent(sourceThreadStopEvent) : 0x%x\n", GetLastError()); } bSourceThreadShouldStop = true; // we make it false only if everything else succeeds sourceThreadHandle = CreateThread(NULL, 0, SourceThreadProc, (void *)this, CREATE_SUSPENDED, &sourceThreadID); if (sourceThreadHandle == NULL) { sourceThreadID = 0; result = -20; break; } result = SourceThreadStarted(sourceThreadHandle, sourceThreadID); if (result != 0) { result = -30; } if (result == 0) // otherwise, if there is an error in SourceThreadStarted, we should stop the thread { bSourceThreadShouldStop = false; } DWORD result = ResumeThread(sourceThreadHandle); if (result == -1) { TerminateThread(sourceThreadHandle, 0); sourceThreadHandle = NULL; sourceThreadID = 0; result = -40; break; } tracer.tracef(ARB, "StartSourceThread : before WaitForSingleObject(sourceThreadStartEvent, INFINITE)\n"); DWORD waitResult = WaitForSingleObject(sourceThreadStartEvent, INFINITE); tracer.tracef(ARB, "StartSourceThread : waitResult = 0x%x\n", waitResult); if (waitResult == WAIT_FAILED) { waitResult = GetLastError(); tracer.tracef(ERR, "StartSourceThread : e-WaitForSingleObject : %d 0x%x\n", waitResult, waitResult); } } while (false); LeaveCriticalSection(&sourceStateMutex); tracer.tracef(ARB, "StartSourceThread : left sourceStateMutex\n"); tracer.tracef(EE, "~StartSourceThread : returning %d\n", result); return result; } int AudioSource::StopSourceThread() { int result(0); bool waitForThread = true; tracer.tracef(EE, "StopSourceThread\n"); EnterCriticalSection(&sourceStartStopMutex); tracer.tracef(ARB, "StopSourceThread : entered sourceStartStopMutex\n"); EnterCriticalSection(&sourceStateMutex); tracer.tracef(ARB, "StopSourceThread : entered sourceStateMutex\n"); do { if (!bSourceThreadRunning) { tracer.tracef(SIG, "StopSourceThread : bSourceThreadRunning = false\n"); result = 0; waitForThread = false; break; } bSourceThreadShouldStop = true; } while (false); LeaveCriticalSection(&sourceStateMutex); tracer.tracef(ARB, "StopSourceThread : left sourceStateMutex\n"); if (waitForThread) { tracer.tracef(ARB, "StopSourceThread : before WaitForSingleObject(sourceThreadStopEvent, INFINITE)\n"); DWORD waitResult = WaitForSingleObject(sourceThreadStopEvent, INFINITE); tracer.tracef(ARB, "StopSourceThread : waitResult = 0x%x\n", waitResult); if (waitResult == WAIT_FAILED) { waitResult = GetLastError(); tracer.tracef(ERR, "StopSourceThread : e-WaitForSingleObject : %d 0x%x\n", waitResult, waitResult); } } LeaveCriticalSection(&sourceStartStopMutex); tracer.tracef(ARB, "StopSourceThread : left sourceStartStopMutex\n"); tracer.tracef(EE, "~StopSourceThread : returning %d\n", result); return result; } DWORD WINAPI AudioSource::SourceThreadProc(LPVOID params) { int result(0); AudioSource *audioSource = (AudioSource *)params; audioSource->tracer.tracef(EE, "SourceThreadProc : begin\n"); audioSource->bSourceThreadRunning = true; SetEvent(audioSource->sourceThreadStartEvent); while (!audioSource->bSourceThreadShouldStop) { AudioSample *pAudioSample = NULL; if ((result = audioSource->GenerateData(&pAudioSample)) < 0) { audioSource->tracer.tracef(ERR, "SourceThreadProc : GenerateData returned %d\n", result); break; } if (!pAudioSample) { audioSource->tracer.tracef(ERR, "SourceThreadProc : GenerateData returned NULL\n"); } EnterCriticalSection(&(audioSource->audioSinksMutex)); vector::iterator iter = (audioSource->audioSinks).begin(); for (iter = (audioSource->audioSinks).begin(); iter != (audioSource->audioSinks).end(); iter++) { int i = audioSource->SendAudioSample(pAudioSample, *iter); } LeaveCriticalSection(&(audioSource->audioSinksMutex)); if (pAudioSample) { pAudioSample->Release(audioSource); pAudioSample = NULL; } } audioSource->tracer.tracef(ARB, "SourceThreadProc : broke out of while loop. bSourceThreadShouldStop = %d\n", audioSource->bSourceThreadShouldStop); audioSource->tracer.tracef(EE, "SourceThreadProc : entering sourceStateMutex\n"); EnterCriticalSection(&(audioSource->sourceStateMutex)); audioSource->bSourceThreadRunning = false; audioSource->tracer.tracef(ARB, "SourceThreadProc : calling SourceThreadStopped\n"); audioSource->SourceThreadStopped(audioSource->sourceThreadHandle, audioSource->sourceThreadID); CloseHandle(audioSource->sourceThreadHandle); audioSource->sourceThreadHandle = NULL; audioSource->sourceThreadID = 0; LeaveCriticalSection(&(audioSource->sourceStateMutex)); audioSource->tracer.tracef(EE, "SourceThreadProc : left sourceStateMutex\n"); audioSource->tracer.tracef(EE, "SourceThreadProc : setting sourceThreadStopEvent and exiting\n"); BOOL setResult = SetEvent(audioSource->sourceThreadStopEvent); return 0; } int AudioSource::SendAudioSample(AudioSample *audioSample, AudioSink *audioSink) { // tracer.tracef(DET, "SendAudioSample : calling TakeNextAudioSample\n"); return audioSink->TakeNextAudioSample(audioSample, this); } int AudioSource::SourceThreadStarted(HANDLE sourceThreadHandle, DWORD sourceThreadID) { return 0; } int AudioSource::SourceThreadStopped(HANDLE sourceThreadHandle, DWORD sourceThreadID) { return 0; } int AudioSource::SourceStarted() { return 0; } int AudioSource::SourceStopped() { return 0; } int AudioSource::GiveNextAudioSample(AudioSample **ppAudioSample, AudioSink *audioSink) { *ppAudioSample = NULL; int result = GenerateData(ppAudioSample); if (result != 0 || *ppAudioSample == NULL) { tracer.tracef(ERR, "GiveNextAudioSample : GenerateData returned error %d, audioSample 0x%x\n", result, *ppAudioSample); if (*ppAudioSample) { (*ppAudioSample)->Release(this); *ppAudioSample = NULL; } } EnterCriticalSection(&audioSinksMutex); vector::iterator iter = audioSinks.begin(); for (iter = audioSinks.begin(); iter != audioSinks.end(); iter++) { if (*(iter) == audioSink) { continue; } SendAudioSample(*ppAudioSample, *iter); } LeaveCriticalSection(&audioSinksMutex); return result; } int AudioSource::GenerateData(AudioSample **audioSample) { tracer.tracef(ERR, "GenerateData : ERROR : Pure Virtual Function Call !!!\n"); return 0; }