// ACMTransformer.cpp: implementation of the ACMTransformer class. // ////////////////////////////////////////////////////////////////////// #include #include #include "ACMTransformer.h" #include "AudioSampleManager.h" #include "AudioSample.h" using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// ACMTransformer::ACMTransformer() { SetSourceFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1)); SetDestinationFormat(WaveFormat::GetWaveFormat(WaveFormat_PCM_16_8_1)); InitializeCriticalSection(&outputQueueMutex); InitializeCriticalSection(&freeBuffersMutex); InitializeCriticalSection(&stateMutex); InitializeCriticalSection(&acmMutex); InitializeCriticalSection(&queryStateMutex); freeBuffersEvent = CreateEvent(NULL, FALSE, FALSE, NULL); outputEnqueueEvent = CreateEvent(NULL, FALSE, FALSE, NULL); outputDequeueEvent = CreateEvent(NULL, FALSE, FALSE, NULL); SetOutputDuration(20); char subFacilityName[100]; sprintf(subFacilityName, "ACMTransformer:%x", this); tracer.SetSubFacilityName(subFacilityName); SetRunning(false); SetTraceLevel(); } ACMTransformer::~ACMTransformer() { tracer.tracef(EE, "~ACMTransformer : begin\n"); DeleteCriticalSection(&outputQueueMutex); DeleteCriticalSection(&freeBuffersMutex); DeleteCriticalSection(&stateMutex); DeleteCriticalSection(&acmMutex); DeleteCriticalSection(&queryStateMutex); CloseHandle(freeBuffersEvent); CloseHandle(outputEnqueueEvent); CloseHandle(outputDequeueEvent); tracer.tracef(EE, "~ACMTransformer : end\n"); } int ACMTransformer::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", "ACMTransformer", 0x100000); } tracer.SetSystemMask(SystemMask); return 0; } int ACMTransformer::SetSourceFormat(WAVEFORMATEX &wfxSource) { sourceFormat = wfxSource; return 0; } int ACMTransformer::SetDestinationFormat(WAVEFORMATEX &wfxDest) { destFormat = wfxDest; return 0; } int ACMTransformer::TransformStarted() { tracer.tracef(EE, "TransformStarted\n"); int result(0); tracer.tracef(ARB, "TransformStarted : entering stateMutex\n"); EnterCriticalSection(&stateMutex); if (IsRunning()) { tracer.tracef(SIG, "TransformStarted : Already running\n"); } else { EnterCriticalSection(&acmMutex); WaveFormat::TraceFormat(&tracer, ARB, sourceFormat); WaveFormat::TraceFormat(&tracer, ARB, destFormat); tracer.tracef(ARB, "TransformStarted : calling acmStreamOpen\n"); result = acmStreamOpen(&hACMStream, NULL, &sourceFormat, &destFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME); LeaveCriticalSection(&acmMutex); if (result == 0) { for (int i=0; i 0) { tracer.tracef(ARB, "TransformStopped : numSources = 0 & numDest = %d\n", numDest); AudioSample *audioSample = NULL; AudioSampleManager::GetInstance()->GetAudioSample(&audioSample, this); if (audioSample) { audioSample->SetFormat(destFormat); int minFrameSize = (audioSample->MinFrameSize() * outputDuration * 1000) / audioSample->MinFrameDuration(); while (true) { tracer.tracef(ARB, "TransformStopped : entering outputQueueMutex\n"); EnterCriticalSection(&outputQueueMutex); if (outputQueue.size() < minFrameSize) { LeaveCriticalSection(&outputQueueMutex); tracer.tracef(ARB, "TransformStopped : left outputQueueMutex\n"); break; } LeaveCriticalSection(&outputQueueMutex); tracer.tracef(ARB, "TransformStopped : left outputQueueMutex. Begin waiting on outputDequeueEvent\n"); WaitForSingleObject(outputDequeueEvent, INFINITE); tracer.tracef(ARB, "TransformStopped : after waiting on outputDequeueEvent\n"); } audioSample->Release(this); audioSample = NULL; } } SetRunning(false); tracer.tracef(ARB, "TransformStopped : entered freeBuffersMutex\n"); EnterCriticalSection(&freeBuffersMutex); freeBuffers.clear(); SetEvent(freeBuffersEvent); tracer.tracef(ARB, "TransformStopped : set freeBuffersEvent\n"); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(ARB, "TransformStopped : left freeBuffersMutex\n"); tracer.tracef(ARB, "TransformStopped : entering outputQueueMutex\n"); EnterCriticalSection(&outputQueueMutex); SetEvent(outputEnqueueEvent); tracer.tracef(ARB, "TransformStopped : set outputEnqueueEvent\n"); SetEvent(outputDequeueEvent); tracer.tracef(ARB, "TransformStopped : set outputDequeueEvent\n"); LeaveCriticalSection(&outputQueueMutex); tracer.tracef(ARB, "TransformStopped : left outputQueueMutex. Unpreparing ACM headers\n"); for (int i=0; i > &data, AudioSample **ppAudioSample) { return 0; } bool ACMTransformer::IsRunning() { EnterCriticalSection(&queryStateMutex); bool result = bRunning; LeaveCriticalSection(&queryStateMutex); return result; } void ACMTransformer::SetRunning(bool running) { EnterCriticalSection(&queryStateMutex); bRunning = running; LeaveCriticalSection(&queryStateMutex); } ACMSTREAMHEADER * ACMTransformer::GetBuffer() { ACMSTREAMHEADER *acmHdr = NULL; while(IsRunning()) { tracer.tracef(ARB, "GetBuffer : entering freeBuffersMutex\n"); EnterCriticalSection(&freeBuffersMutex); if (freeBuffers.size() > 0) { acmHdr = freeBuffers.front(); freeBuffers.pop_front(); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(ARB, "GetBuffer : left freeBuffersMutex\n"); break; } else { LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(ARB, "GetBuffer : left freeBuffersMutex\n"); tracer.tracef(ARB, "GetBuffer : before waiting for freeBuffersEvent\n"); WaitForSingleObject(freeBuffersEvent, INFINITE); tracer.tracef(ARB, "GetBuffer : after waiting for freeBuffersEvent\n"); } } return acmHdr; } void ACMTransformer::ReleaseBuffer(ACMSTREAMHEADER *acmHdr) { tracer.tracef(ARB, "ReleaseBuffer : entering freeBuffersMutex\n"); EnterCriticalSection(&freeBuffersMutex); freeBuffers.push_back(acmHdr); SetEvent(freeBuffersEvent); tracer.tracef(ARB, "ReleaseBuffer : set freeBuffersEvent\n"); LeaveCriticalSection(&freeBuffersMutex); tracer.tracef(ARB, "ReleaseBuffer : left freeBuffersMutex\n"); } int ACMTransformer::RenderAudioSamples(std::vector > &data) { tracer.tracef(DET, "RenderAudioSamples\n"); int result(0); AudioSample *inSample = NULL; if (data.size() > 0) { inSample = data[0].first; } if (inSample && IsRunning()) { if (inSample->DataSize() > 0) { ACMSTREAMHEADER *acmHdr = GetBuffer(); if (acmHdr) { int extraBytes = acmHdr->cbSrcLength - acmHdr->cbSrcLengthUsed; int totalBytes = inSample->DataSize() + extraBytes; if ( totalBytes > 0 && totalBytes <= ACMTRANSFORMER_MAX_SOURCEBUFFERSIZE) { acmHdr->cbSrcLength = totalBytes; memcpy(acmHdr->pbSrc, acmHdr->pbSrc + acmHdr->cbSrcLengthUsed, extraBytes); memcpy(acmHdr->pbSrc + extraBytes, inSample->Data(), inSample->DataSize()); EnterCriticalSection(&acmMutex); result = acmStreamConvert(hACMStream, acmHdr, ACM_STREAMCONVERTF_BLOCKALIGN); if (result != 0) { LeaveCriticalSection(&acmMutex); ReleaseBuffer(acmHdr); tracer.tracef(ERR, "RenderAudioSamples : acmStreamConvert failed with error code %d 0x%x\n", result, result); result = -10; Sleep(outputDuration); } else if (acmHdr->cbDstLengthUsed > 0) { unsigned char convertedData[ACMTRANSFORMER_MAX_DESTBUFFERSIZE]; memcpy(convertedData, acmHdr->pbDst, acmHdr->cbDstLengthUsed); LeaveCriticalSection(&acmMutex); ReleaseBuffer(acmHdr); AddConvertedData(convertedData, acmHdr->cbDstLengthUsed); // AddConvertedData(acmHdr->pbDst, acmHdr->cbDstLengthUsed); } else { LeaveCriticalSection(&acmMutex); ReleaseBuffer(acmHdr); } } else { ReleaseBuffer(acmHdr); Sleep(outputDuration); result = -20; } } else { Sleep(outputDuration); result = -30; } } else { Sleep(inSample->GetSilenceDuration()); result = -40; } } else { Sleep(outputDuration); result = -50; } tracer.tracef(DET, "~RenderAudioSamples : %d\n", result); return result; } int ACMTransformer::GenerateData(AudioSample **ppAudioSample) { tracer.tracef(DET, "GenerateData\n"); int result(0); *ppAudioSample = NULL; AudioSample *audioSample = NULL; (AudioSampleManager::GetInstance())->GetAudioSample(&audioSample, this); if (audioSample) { audioSample->SetFormat(destFormat); audioSample->SetDataSize(0); audioSample->SetSilenceDuration(outputDuration); int numBytesToWrite = (audioSample->MinFrameSize() * outputDuration * 1000) / audioSample->MinFrameDuration(); if (IsRunning()) { tracer.tracef(DET, "GenerateData : entering outputQueueMutex. Filter running\n"); EnterCriticalSection(&outputQueueMutex); if (outputQueue.size() < numBytesToWrite) { LeaveCriticalSection(&outputQueueMutex); tracer.tracef(DET, "GenerateData : left outputQueueMutex\n"); result = -10; } else { int numBytesToCopy = min(numBytesToWrite, audioSample->BufferSize()); for (int i=0; iData())[i] = c; } SetEvent(outputDequeueEvent); tracer.tracef(DET, "GenerateData : set outputDequeueEvent\n"); LeaveCriticalSection(&outputQueueMutex); tracer.tracef(DET, "GenerateData : left outputQueueMutex\n"); audioSample->SetDataSize(numBytesToCopy); } } else { tracer.tracef(DET, "GenerateData : entering outputQueueMutex\n"); EnterCriticalSection(&outputQueueMutex); SetEvent(outputDequeueEvent); tracer.tracef(DET, "GenerateData : set outputDequeueEvent\n"); LeaveCriticalSection(&outputQueueMutex); tracer.tracef(DET, "GenerateData : left outputQueueMutex\n"); result = -20; } } else { tracer.tracef(ERR, "GenerateData : could not get audioSample from manager\n"); result = -30; } if (result != 0) { if (audioSample) { audioSample->Release(this); audioSample = NULL; } } *ppAudioSample = audioSample; if (result == 0) { tracer.tracef(DET, "~GenerateData : 0x%x\n", *ppAudioSample); } else { tracer.tracef(ERR, "~GenerateData : %d, 0x%x\n", result, *ppAudioSample); } return result; } int ACMTransformer::AddConvertedData(unsigned char *dataIn, int numBytes) { while (true) { if (IsRunning()) { tracer.tracef(DET, "AddConvertedData : entering outputQueueMutex\n"); EnterCriticalSection(&outputQueueMutex); int queueSpace = ACMTRANSFORMER_OUTPUTBUFFERSIZE - outputQueue.size(); if (queueSpace >= numBytes) { for (int i=0; icbDstLengthUsed > 0) { acmTransformer->AddConvertedData(acmHdr->pbDst, acmHdr->cbDstLengthUsed); } acmTransformer->ReleaseBuffer(acmHdr); break; default: break; } }