// WaveFileSource.cpp: implementation of the WaveFileSource class. // ////////////////////////////////////////////////////////////////////// #include "WaveFileSource.h" #include "AudioSampleManager.h" #include "AudioSample.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// WaveFileSource::WaveFileSource() { szFileName[0] = '\0'; pFormat = NULL; bufferDuration = WAVEFILESOURCE_DEFAULT_BUFFERDURATION; char subFacilityName[100]; sprintf(subFacilityName, "WaveFileSource:%x", this); tracer.SetSubFacilityName(subFacilityName); SetTraceLevel(); tracer.tracef(EE, "Constructor - begin\n"); PlayOnce(); bRunning = false; InitializeCriticalSection(&filterMutex); hmmio = NULL; tracer.tracef(EE, "Constructor - end\n"); } WaveFileSource::~WaveFileSource() { tracer.tracef(EE, "Destructor - begin\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveFileSource~ : entered filterMutex\n"); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "WaveFileSource~ : left filterMutex\n"); CloseMMIO(); DeleteCriticalSection(&filterMutex); tracer.tracef(EE, "Destructor - end\n"); } int WaveFileSource::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", "WaveFileSource", 0x100000); } tracer.SetSystemMask(SystemMask); return 0; } int WaveFileSource::PlayInLoop() { looping = true; return 0; } int WaveFileSource::PlayOnce() { looping = false; return 0; } int WaveFileSource::OpenWaveFile(const char *inputFileName) { int result(0); PlayOnce(); if (strlen(inputFileName) < 128 && !bRunning) { do { CloseMMIO(); strcpy(szFileName, inputFileName); // Open the file for reading with buffered I/O // by using the default internal buffer if(!(hmmio = mmioOpen(szFileName, NULL, MMIO_READ | MMIO_ALLOCBUF))) { tracer.tracef(ERR, "SourceStarted : mmioOpen(%s) returned 0x%x\n", szFileName, hmmio); result = -10; break; } MMIOINFO mmInfoStart; mmioGetInfo(hmmio, &mmInfoStart, 0); LONG fileStartPosition = (LONG)mmInfoStart.pchNext; // Locate a "RIFF" chunk with a "WAVE" form type to make // sure the file is a waveform-audio file. mmckinfoParent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hmmio, (LPMMCKINFO) &mmckinfoParent, NULL, MMIO_FINDRIFF)) { tracer.tracef(ERR, "SourceStarted : %s not wave file", szFileName); result = -20; break; } // Find the "FMT" chunk (form type "FMT"); it must be // a subchunk of the "RIFF" chunk. mmckinfoSubchunk.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK)) { tracer.tracef(ERR, "SourceStarted : File %s has no FMT chunk", szFileName); result = -30; break; } // Get the size of the "FMT" chunk. Allocate // and lock memory for it. dwFmtSize = mmckinfoSubchunk.cksize; pFormat = (WAVEFORMATEX *) new char[dwFmtSize]; // Read the "FMT" chunk. if (mmioRead(hmmio, (HPSTR) pFormat, dwFmtSize) != dwFmtSize) { tracer.tracef(ERR, "SourceStarted : Failed to read format chunk"); result = -40; break; } // Ascend out of the "FMT" subchunk. mmioAscend(hmmio, &mmckinfoSubchunk, 0); // Find the data subchunk. The current file position should be at // the beginning of the data chunk; however, you should not make // this assumption. Use mmioDescend to locate the data chunk. mmckinfoSubchunk.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(hmmio, &mmckinfoSubchunk, &mmckinfoParent, MMIO_FINDCHUNK)) { tracer.tracef(ERR, "SourceStarted : File %s has no data chunk", szFileName); result = -50; break; } // Get the size of the data subchunk. dwDataSize = mmckinfoSubchunk.cksize; if (dwDataSize == 0L) { tracer.tracef(ERR, "SourceStarted : Data chunk of %s contains no data", szFileName); result = -60; break; } MMIOINFO mmInfo; mmioGetInfo(hmmio, &mmInfo, 0); dataStartPosition = (LONG)mmInfo.pchNext - fileStartPosition; } while(false); if (result != 0) { CloseMMIO(); } } else { if (bRunning) { result = -70; } else { result = -80; } } return result; } int WaveFileSource::CloseMMIO() { if (hmmio) { mmioClose(hmmio, 0); } hmmio = NULL; if (pFormat) { delete [] (char *)pFormat; } pFormat = NULL; return 0; } int WaveFileSource::SourceStarted() { int result(0); int returnCode(0); tracer.tracef(EE, "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; } if (!hmmio || !pFormat) { tracer.tracef(ERR, "SourceStarted : e-error : hmmio = 0x%x, pFormat = 0x%x\n", hmmio, pFormat); result = -20; break; } bRunning = true; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStarted : left filterMutex\n"); tracer.tracef(EE, "~SourceStarted : returning %d\n", result); return result; } int WaveFileSource::SourceStopped() { int result(0); int returnCode(0); tracer.tracef(EE, "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 = CloseMMIO(); if (returnCode != 0) { tracer.tracef(ERR, "SourceStopped : e-CloseMMIO : %d 0x%x\n", returnCode, returnCode); result = -20; break; } bRunning = false; } while (false); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceStopped : left filterMutex\n"); tracer.tracef(EE, "~SourceStopped : returning %d\n", result); return result; } int WaveFileSource::SourceThreadStarted(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); tracer.tracef(EE, "SourceThreadStarted\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStarted : entered filterMutex\n"); do { if (!hmmio || !pFormat) { tracer.tracef(ERR, "SourceThreadStarted : e-error : hmmio = 0x%x, pFormat = 0x%x\n", hmmio, pFormat); result = -10; break; } bRunning = true; } while (false); tracer.tracef(ARB, "SourceThreadStarted : before firing FILE_STARTED %s\n", szFileName); FireEvent(FILE_STARTED, szFileName); tracer.tracef(ARB, "SourceThreadStarted : after firing FILE_STARTED %s\n", szFileName); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStarted : left filterMutex\n"); tracer.tracef(EE, "~SourceThreadStarted : returning %d\n", result); return result; } int WaveFileSource::SourceThreadStopped(HANDLE sourceThreadHandle, DWORD sourceThreadID) { int result(0); int returnCode(0); tracer.tracef(EE, "SourceThreadStopped\n"); EnterCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStopped : entered filterMutex\n"); do { returnCode = CloseMMIO(); if (returnCode != 0) { tracer.tracef(ERR, "SourceThreadStopped : e-CloseMMIO : %d 0x%x\n", returnCode, returnCode); result = -10; break; } bRunning = false; } while (false); tracer.tracef(ARB, "SourceThreadStopped : before firing FILE_STOPPED %s\n", szFileName); FireEvent(FILE_STOPPED, szFileName); tracer.tracef(ARB, "SourceThreadStopped : after firing FILE_STOPPED %s\n", szFileName); LeaveCriticalSection(&filterMutex); tracer.tracef(ARB, "SourceThreadStopped : left filterMutex\n"); tracer.tracef(EE, "~SourceThreadStopped : returning %d\n", result); return result; } int WaveFileSource::GetFormat(WAVEFORMATEX *waveFormat) { if (pFormat) { *waveFormat = *pFormat; } return 0; } int WaveFileSource::SetBufferDuration(int bufferDurationMillisec) { bufferDuration = bufferDurationMillisec; return 0; } int WaveFileSource::GenerateData(AudioSample **ppAudioSample) { tracer.tracef(DET, "GenerateData\n"); int result(0); AudioSample *audioSample = NULL; result = (AudioSampleManager::GetInstance())->GetAudioSample(&audioSample, this); *ppAudioSample = NULL; if (audioSample) { audioSample->SetDataSize(0); audioSample->SetSilenceDuration(bufferDuration); if (bRunning) { audioSample->SetFormat(*pFormat); int nBytesToRead = (pFormat->nAvgBytesPerSec * bufferDuration) / 1000; if (audioSample->BufferSize() < nBytesToRead) { result = -20; } else { int bytes(0); if((bytes = mmioRead(hmmio, (HPSTR) audioSample->Data(), nBytesToRead)) != nBytesToRead) { if (bytes < 0 || (bytes == 0 && !looping)) { bytes = 0; result = -30; } else if (looping) { mmioSeek(hmmio, dataStartPosition, SEEK_SET); int nBytes = mmioRead(hmmio, (HPSTR) audioSample->Data(), nBytesToRead - bytes); if (nBytes <= 0) { result = -40; } else { bytes += nBytes; } } audioSample->SetDataSize(bytes); } else { audioSample->SetDataSize(nBytesToRead); } } } } if (result < 0) { if (audioSample) { audioSample->Release(this); audioSample = NULL; } } *ppAudioSample = audioSample; if (*ppAudioSample) { tracer.tracef(DET, "~GenerateData : data %d bytes, silence %d ms\n", audioSample->DataSize(), audioSample->GetSilenceDuration()); } else { tracer.tracef(DET, "~GenerateData : returning NULL : result = %d\n", result); } return result; } int WaveFileSource::AddFilePlayListener(WaveFileSourceListener *waveFileSourceListener) { return AddListener((void *)waveFileSourceListener); } int WaveFileSource::RemoveFilePlayListener(WaveFileSourceListener *waveFileSourceListener) { return RemoveListener((void *)waveFileSourceListener); } int WaveFileSource::FireEvent(int eventType, char *waveFileName) { EnterCriticalSection(&listenersMutex); std::vector::iterator iter = listeners.begin(); while (iter != listeners.end()) { switch(eventType) { case FILE_STARTED: ((WaveFileSourceListener *)(*iter))->FilePlayStarted(this, waveFileName); break; case FILE_STOPPED: ((WaveFileSourceListener *)(*iter))->FilePlayStopped(this, waveFileName); break; default: break; } iter++; } LeaveCriticalSection(&listenersMutex); /* FireEventThreadParams *params = new FireEventThreadParams(); params->eventType = eventType; params->waveFileSource = this; strncpy(params->waveFileName, waveFileName, min(strlen(waveFileName)+1, 1024)); (params->waveFileName)[1024] = '\0'; DWORD threadID; CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FireEventThread, (LPVOID)params, 0, &threadID); */ return 0; } DWORD WINAPI WaveFileSource::FireEventThread(LPVOID param) { FireEventThreadParams *params = (FireEventThreadParams *)param; WaveFileSource *waveFileSource = params->waveFileSource; EnterCriticalSection(&(waveFileSource->listenersMutex)); std::vector::iterator iter = waveFileSource->listeners.begin(); while (iter != waveFileSource->listeners.end()) { switch(params->eventType) { case FILE_STARTED: ((WaveFileSourceListener *)(*iter))->FilePlayStarted(waveFileSource, params->waveFileName); break; case FILE_STOPPED: ((WaveFileSourceListener *)(*iter))->FilePlayStopped(waveFileSource, params->waveFileName); break; default: break; } iter++; } LeaveCriticalSection(&(waveFileSource->listenersMutex)); return 0; } void WaveFileSourceListener::FilePlayStarted(WaveFileSource *waveFileSource, char *waveFileName) { // AfxMessageBox("WaveFileSourceListener::FilePlayStarted : ERROR : pure virtual function call !!!\n"); } void WaveFileSourceListener::FilePlayStopped(WaveFileSource *waveFileSource, char *waveFileName) { // AfxMessageBox("WaveFileSourceListener::FilePlaySopped : ERROR : pure virtual function call !!!\n"); }