// AudioSource.cpp: implementation of the AudioSource class.
|
//
|
//////////////////////////////////////////////////////////////////////
|
|
#include <algorithm>
|
#include <iostream>
|
|
#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<AudioSink *>::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<AudioSink *>::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<AudioSink *>::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;
|
}
|