// WaveAudioSource.cpp: implementation of the WaveAudioSource class. // ////////////////////////////////////////////////////////////////////// #include "AudioSample.h" #include "AudioSampleManager.h" #include "WaveAudioSource.h" using namespace std; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// WaveAudioSource::WaveAudioSource() { char subFacilityName[100]; sprintf(subFacilityName, "WaveAudioSource:%x", this); tracer.SetSubFacilityName(subFacilityName); SetTraceLevel(); tracer.tracef(EE, "Constructor begin\n"); numBuffers = WAVESOURCE_NUM_WAVEHDR; bufferSize = WAVESOURCE_DEFAULT_WAVEHDR_SIZE; InitializeCriticalSection(&waveInMutex); InitializeCriticalSection(&bufferListMutex); InitializeCriticalSection(&filterMutex); dataEvent = CreateEvent(NULL, FALSE, FALSE, NULL); bEnableAddBuffer = false; hWaveIn = NULL; waveinDeviceID = WAVE_MAPPER; buffersToAdd.clear(); bRunning = false; needToSetVolume = false; micVolume = 0; // set default format SetFormat(WaveFormat_PCM_16_8_1); } WaveAudioSource::~WaveAudioSource() { tracer.tracef(EE, "Destructor begin\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveAudioSource~ : entered filterMutex\n"); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveAudioSource~ : left filterMutex\n"); DeleteCriticalSection(&waveInMutex); DeleteCriticalSection(&bufferListMutex); DeleteCriticalSection(&filterMutex); CloseHandle(dataEvent); tracer.tracef(EE, "Destructor end\n"); } int WaveAudioSource::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", "WaveAudioSource", 0x100000); } tracer.SetSystemMask(SystemMask); return 0; } int WaveAudioSource::SetFormat(int waveFormatNumber) { tracer.tracef(EE, "SetFormat %d : bRunning = %d\n", waveFormatNumber, bRunning); if (!bRunning) { format = WaveFormat::GetWaveFormat(waveFormatNumber); } tracer.tracef(EE, "~SetFormat\n"); return 0; } int WaveAudioSource::SetVolume(unsigned long vvolume) { if (bRunning) { MMRESULT rc; // Return code. HMIXER hMixer; // Mixer handle used in mixer API calls. MIXERCONTROL mxc; // Holds the mixer control data. MIXERLINE mxl; // Holds the mixer line data. MIXERLINECONTROLS mxlc; // Obtains the mixer control. bool volumeChanged = false; // Open the mixer. This opens the mixer with a deviceID of 0. If you // have a single sound card/mixer, then this will open it. If you have // multiple sound cards/mixers, the deviceIDs will be 0, 1, 2, and // so on. rc = mixerOpen(&hMixer, (UINT)hWaveIn, 0, 0, MIXER_OBJECTF_HWAVEIN); if (MMSYSERR_NOERROR == rc) { tracer.tracef(DET, "SetVolume : mixerOpen succeeded\n"); do { // Initialize MIXERLINE structure. ZeroMemory(&mxl,sizeof(mxl)); mxl.cbStruct = sizeof(mxl); // Specify the line you want to get. You are getting the input line // here. If you want to get the output line, you need to use // MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT. mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN; rc = mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE); if (MMSYSERR_NOERROR != rc) { tracer.tracef(ERR, "SetVolume : e-mixerGetLineInfo((HMIXEROBJ)hMixer, &mxl, MIXER_GETLINEINFOF_COMPONENTTYPE) : %d\n", rc); break; } // now find out the microphone input for that line (the ADC) int numConnections = mxl.cConnections; tracer.tracef(DET, "SetVolume : mixerGetLineInfo succeeded. numConnections = %d\n", numConnections); DWORD destinationLineID = mxl.dwDestination; for (int j=0; jtracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback\n"); switch(uMsg) { case WIM_OPEN: (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback : WIM_OPEN\n"); break; case WIM_CLOSE: (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback : WIM_CLOSE\n"); SetEvent(waveAudioSource->dataEvent); break; case WIM_DATA: wHdr = (WAVEHDR *)dwParam1; (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback : WIM_DATA %d\n", wHdr->dwUser); (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback : Entering bufferListMutex\n"); EnterCriticalSection(&(waveAudioSource->bufferListMutex)); (waveAudioSource->buffersToAdd).push_back(wHdr); LeaveCriticalSection(&(waveAudioSource->bufferListMutex)); SetEvent(waveAudioSource->dataEvent); // we do this within the critical section because fillbuffer resets this within the same critical section - ??? so i go it out (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "WaveInCallback : Left bufferListMutex\n"); break; default: break; } (waveAudioSource->tracer).tracef(SDI_LEVEL_DETAILED, "~WaveInCallback\n"); } int WaveAudioSource::GenerateData(AudioSample **ppAudioSample) { tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData\n"); HRESULT result = NOERROR; *ppAudioSample = NULL; bool fireDataEvent = false; while (true) { tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : Entering waveInMutex\n"); EnterCriticalSection(&waveInMutex); bool bEnabled = bEnableAddBuffer; LeaveCriticalSection(&waveInMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : Left waveInMutex\n"); if (!bEnabled) { if (fireDataEvent) { SetEvent(dataEvent); } break; } tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : Entering bufferListMutex\n"); EnterCriticalSection(&bufferListMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : buffersToAdd.size = %d\n", buffersToAdd.size()); if (buffersToAdd.size() <= 0) { LeaveCriticalSection(&bufferListMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : Left bufferListMutex. Waiting for dataEvent\n"); WaitForSingleObject(dataEvent, INFINITE); tracer.tracef(DET, "GenerateData : Got dataEvent\n"); fireDataEvent = true; continue; } else { WAVEHDR *wHdr = buffersToAdd.front(); buffersToAdd.pop_front(); LeaveCriticalSection(&bufferListMutex); tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : Left bufferListMutex\n"); AudioSample *audioSample; audioSampleManager->GetAudioSample(&audioSample, this); *ppAudioSample = audioSample; audioSample->SetFormat(format); int bytesToFill = min(wHdr->dwBytesRecorded, audioSample->BufferSize()); audioSample->SetDataSize(bytesToFill); // check to see if the audio is loud enough int bytesPerSample = format.wBitsPerSample / 8; int numSamples = bytesToFill / bytesPerSample; double total = 0; bool canEncode = false; for (int i=0; ilpData) + i)); break; case 2: sampleValue = *((short *)((char *)(wHdr->lpData) + i)); break; case 4: sampleValue = *((int *)((char *)(wHdr->lpData) + i)); break; } if (abs(sampleValue) > 4) { canEncode = true; break; } } if (micVolume > 0 && canEncode) { tracer.tracef(SDI_LEVEL_DETAILED, "GenerateData : memcpy(0x%x, 0x%x, %d)\n", audioSample->Data(), wHdr->lpData, bytesToFill); memcpy(audioSample->Data(), wHdr->lpData, bytesToFill); } else { audioSample->SetSilenceDuration(audioSample->GetDuration()); audioSample->SetDataSize(0); } AddBuffer(wHdr->dwUser); break; } } tracer.tracef(SDI_LEVEL_DETAILED, "~GenerateData\n"); return 0; } int WaveAudioSource::SourceStarted() { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceStarted\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStarted : entered filterMutex\n"); do { if (bRunning) { tracer.tracef(ERR, "SourceStarted : e-error : already running\n"); result = -10; break; } returnCode = BeginAudioCapture(); if (returnCode != 0) { tracer.tracef(ERR, "SourceStarted : e-BeginAudioCapture : %d 0x%x\n", returnCode, returnCode); result = -20; break; } if (needToSetVolume) { SetVolume(micVolume); needToSetVolume = false; } bRunning = true; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStarted : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceStarted : returning %d\n", result); return result; } int WaveAudioSource::SourceStopped() { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceStopped\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStopped : entered filterMutex\n"); do { if (!bRunning) { tracer.tracef(ERR, "SourceStopped : e-error : not running\n"); result = -10; break; } returnCode = EndAudioCapture(); if (returnCode != 0) { tracer.tracef(ERR, "SourceStopped : e-EndAudioCapture : %d 0x%x\n", returnCode, returnCode); result = -20; break; } needToSetVolume = false; bRunning = false; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStopped : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceStopped : returning %d\n", result); return result; } int WaveAudioSource::SourceThreadStarted(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); SetTraceLevel(); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceThreadStarted\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStarted : entered filterMutex\n"); do { returnCode = SetThreadPriority(sourceThreadHandle, THREAD_PRIORITY_TIME_CRITICAL); if (returnCode == 0) { returnCode = GetLastError(); tracer.tracef(ERR, "SourceThreadStarted : e-SetThreadPriority : %d 0x%x\n", returnCode, returnCode); } returnCode = BeginAudioCapture(); if (returnCode != 0) { tracer.tracef(ERR, "SourceThreadStarted : e-BeginAudioCapture : %d 0x%x\n", returnCode, returnCode); result = -10; break; } if (needToSetVolume) { SetVolume(micVolume); needToSetVolume = false; } bRunning = true; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStarted : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceThreadStarted : returning %d\n", result); return result; } int WaveAudioSource::SourceThreadStopped(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "SourceThreadStopped\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStopped : entered filterMutex\n"); do { if (!bRunning) { tracer.tracef(ERR, "SourceThreadStopped : not running\n"); result = -10; break; } returnCode = EndAudioCapture(); if (returnCode != 0) { tracer.tracef(ERR, "SourceThreadStopped : e-EndAudioCapture : %d 0x%x\n", returnCode, returnCode); result = -20; break; } needToSetVolume = false; bRunning = false; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStopped : left filterMutex\n"); tracer.tracef(SDI_LEVEL_ENTRY_EXIT, "~SourceThreadStopped : returning %d\n", result); return result; }