/* ////////////////////////// PUBLIC STATIC ///////////////////////////////// */ UtlString MpidWinMM::getDefaultDeviceName() { UtlString devName = ""; // Get windows default input device name unsigned nDevs = waveInGetNumDevs(); if (nDevs == 0) { OsSysLog::add(FAC_AUDIO, PRI_ERR, "MpidWinMM::getDefaultDeviceName: " "No input audio devices present!"); } assert(nDevs != 0); MMRESULT wavResult = MMSYSERR_NOERROR; WAVEINCAPS devCaps; int defaultWinDeviceId = 0; wavResult = waveInGetDevCaps(defaultWinDeviceId, &devCaps, sizeof(devCaps)); if (wavResult != MMSYSERR_NOERROR) { OsSysLog::add(FAC_AUDIO, PRI_ERR, "MpodWinMM::getDefaultDeviceName: " "Couldn't get default input device capabilities!"); showWaveError("WINDOWS_DEFAULT_DEVICE_HACK", wavResult, -1, __LINE__); } else { devName = devCaps.szPname; } assert(wavResult == MMSYSERR_NOERROR); return devName; }
// This function will attempt to open a user specified audio device. // If it fails, we will try to open any audio device that meets our requested format // If we still fail, we will return 0, and display a message. // TODO: Seems we have a problem when no audio device can be found. No calls can be made. // I recommend we bubble this up to java and display a message. static int openAudioOut(int desiredDeviceId, HWAVEOUT *pAudioOutH,int nChannels, int nSamplesPerSec, int nBitsPerSample) { WAVEFORMATEX fmt; MMRESULT res; *pAudioOutH = NULL; fmt.wFormatTag = WAVE_FORMAT_PCM; fmt.nChannels = nChannels; fmt.nSamplesPerSec = nSamplesPerSec; fmt.nAvgBytesPerSec = (nChannels * nSamplesPerSec * nBitsPerSample) / 8; fmt.nBlockAlign = (nChannels * nBitsPerSample) / 8; fmt.wBitsPerSample = nBitsPerSample; fmt.cbSize = 0; res = waveOutOpen( pAudioOutH, // handle (will be filled in) desiredDeviceId, // select the device specified by user &fmt, // format (DWORD) speakerCallbackProc,// callback entry GetCurrentThreadId(), // instance data CALLBACK_FUNCTION); // callback function specified //if we fail to open the audio device above, then we //will try to open any device that will hande the requested format if (res != MMSYSERR_NOERROR) res = waveOutOpen( pAudioOutH, // handle (will be filled in) WAVE_MAPPER, // select any device able to handle this format &fmt, // format (DWORD) speakerCallbackProc,// callback entry GetCurrentThreadId(), // instance data CALLBACK_FUNCTION); // callback function specified if (res != MMSYSERR_NOERROR) { //hmm, couldn't open any audio device... things don't look good at this point showWaveError("waveOutOpen", res, -1, __LINE__); waveOutClose(*pAudioOutH); *pAudioOutH = NULL; return 0; } else { return 1; } }
void MpidWinMM::processAudioInput(HWAVEIN hwi, UINT uMsg, void* dwParam1) { if (!mIsOpen) { assert(uMsg == WIM_OPEN); if (uMsg == WIM_OPEN) { // printf("received WIM_OPEN\n"); fflush(stdout); mIsOpen = TRUE; } } if (uMsg == WIM_DATA) { // printf("received WIM_DATA\n"); fflush(stdout); assert(mIsOpen); WAVEHDR* pWaveHdr = (WAVEHDR*)dwParam1; assert(pWaveHdr->dwBufferLength == (mSamplesPerFrame*sizeof(MpAudioSample))); assert(pWaveHdr->lpData != NULL); // Only process if we're enabled.. if(mIsEnabled) { #ifdef TEST_PRINT OsSysLog::add(FAC_MP, PRI_DEBUG, "MpidWinMM::processAudioInput got frame device: %d (%s)", getDeviceId(), getDeviceName().data()); #endif mpInputDeviceManager->pushFrame(mDeviceId, mSamplesPerFrame, (MpAudioSample*)pWaveHdr->lpData, mCurrentFrameTime); // Ok, we have received and pushed a frame to the manager, // Now we advance the frame time. mCurrentFrameTime += (mSamplesPerFrame*1000)/mSamplesPerSec; } else { OsSysLog::add(FAC_MP, PRI_DEBUG, "MpidWinMM::processAudioInput input device: %d (%s) disabled", getDeviceId(), getDeviceName().data()); } if(mIsEnabled) { // Put the wave header back in the pool.. MMRESULT res = MMSYSERR_NOERROR; res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { showWaveError("waveInAddBuffer", res, -1, __LINE__); mnAddBufferFailures++; if(mnAddBufferFailures >= mNumInBuffers) { waveInClose(mDevHandle); mDevHandle = NULL; mWinMMDeviceId = -1; } } } } else if (uMsg == WIM_CLOSE) { // printf("received WIM_CLOSE\n"); fflush(stdout); mIsOpen = FALSE; } }
OsStatus MpidWinMM::disableDevice() { OsStatus status = OS_SUCCESS; MMRESULT res; if (!isDeviceValid() || !isEnabled()) { return OS_FAILED; } // Indicate we are no longer enabled -- Do this first, // since we'll be partially disabled from here on out. // It is very important that this happen *before* waveInReset, // as the callback will continue to add and process buffers // while waveInReset is called causing a deadlock. mIsEnabled = FALSE; // Cleanup if (mDevHandle == NULL) { return OS_INVALID_STATE; } // Reset performs a stop, resets the buffers, and marks them // for being sent to the callback. // The remaining data in the windows buffers *IS* sent to the callback, // So be sure to watch for it and drop it on the floor. res = waveInReset(mDevHandle); if (res != MMSYSERR_NOERROR) { showWaveError("waveInReset", res, -1, __LINE__); } // Must unprepare the headers after a reset, but before the device is closed // (if this is done after waveInClose, mDevHandle will be invalid and // MMSYSERR_INVALHANDLE will be returned. unsigned i; for (i=0; i < mNumInBuffers; i++) { res = waveInUnprepareHeader(mDevHandle, &mpWaveHeaders[i], sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { showWaveError("waveInUnprepareHeader", res, i, __LINE__); } } res = waveInClose(mDevHandle); if (res != MMSYSERR_NOERROR) { showWaveError("waveInClose", res, -1, __LINE__); } // Delete the buffers that were allocated in enableDevice() for (i = 0; i < mNumInBuffers; i++) { delete[] mpWaveBuffers[i]; mpWaveBuffers[i] = NULL; } // set the device handle to NULL, since it no longer is valid. mDevHandle = NULL; // Clear out all the wave header information. mSamplesPerFrame = 0; mSamplesPerSec = 0; mCurrentFrameTime = 0; return status; }
OsStatus MpidWinMM::enableDevice(unsigned samplesPerFrame, unsigned samplesPerSec, MpFrameTime currentFrameTime) { OsStatus status = OS_SUCCESS; // reset the number of addBuffer failures, as we're starting fresh now. mnAddBufferFailures = 0; // If the device is not valid, let the user know it's bad. if (!isDeviceValid()) { return OS_INVALID_STATE; // perhaps new OsState of OS_RESOURCE_INVALID? } if (isEnabled()) { return OS_FAILED; } // Set some wave header stat information. mSamplesPerFrame = samplesPerFrame; mSamplesPerSec = samplesPerSec; mCurrentFrameTime = currentFrameTime; // Do stuff to enable device. int nChannels = 1; WAVEFORMATEX wavFormat; wavFormat.wFormatTag = WAVE_FORMAT_PCM; wavFormat.nChannels = nChannels; wavFormat.nSamplesPerSec = mSamplesPerSec; wavFormat.nAvgBytesPerSec = nChannels * mSamplesPerSec * sizeof(MpAudioSample); wavFormat.nBlockAlign = nChannels * sizeof(MpAudioSample); wavFormat.wBitsPerSample = sizeof(MpAudioSample) * 8; wavFormat.cbSize = 0; // Tell windows to open the input audio device. This doesn't // tell it to send the data to our callback yet, just to get it ready // to do so.. MMRESULT res = waveInOpen(&mDevHandle, mWinMMDeviceId, &wavFormat, (CBTYPE)waveInCallbackStatic, (CBTYPE)this, CALLBACK_FUNCTION); if (res != MMSYSERR_NOERROR) { // If waveInOpen failed, print out the error info, // invalidate the handle, and the device driver itself, status = OS_FAILED; showWaveError("MpidWinMM::enableDevice", res, -1, __LINE__); waveInClose(mDevHandle); mDevHandle = NULL; // Open didn't work, reset device handle to NULL mWinMMDeviceId = -1; // Make device invalid. // and return OS_FAILED. return status; } // Allocate the buffers we are going to use to receive audio data from // the windows audio input callback. // Calculate the buffer length we're going to use. // number of samples per frame * sample size in bytes mWaveBufSize = mSamplesPerFrame * sizeof(MpAudioSample); unsigned i; for (i = 0; i < mNumInBuffers; i++) { mpWaveBuffers[i] = new char[mWaveBufSize]; } // Setup the buffers so windows can stuff them full of audio // when it becomes available from this audio input device. WAVEHDR* pWaveHdr = NULL; for (i=0; i < mNumInBuffers; i++) { pWaveHdr = initWaveHeader(i); res = waveInPrepareHeader(mDevHandle, pWaveHdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { showWaveError("waveInPrepareHeader", res, i, __LINE__); waveInClose(mDevHandle); mDevHandle = NULL; mWinMMDeviceId = -1; // and return OS_FAILED. return status; } res = waveInAddBuffer(mDevHandle, pWaveHdr, sizeof(WAVEHDR)); if (res != MMSYSERR_NOERROR) { showWaveError("waveInAddBuffer", res, i, __LINE__); waveInClose(mDevHandle); mDevHandle = NULL; mWinMMDeviceId = -1; // and return OS_FAILED. return status; } } // Tell windows to start sending audio data to the callback. res = waveInStart(mDevHandle); if (res != MMSYSERR_NOERROR) { // If waveInStart failed, print out the error info, // invalidate the handle and the device driver itself, status = OS_FAILED; showWaveError("waveInStart", res, -1, __LINE__); waveInClose(mDevHandle); mDevHandle = NULL; mWinMMDeviceId = -1; // and return OS_FAILED. return status; } // If enableDevice failed, return indicating failure. if (status == OS_SUCCESS) { mIsEnabled = TRUE; } return status; }
unsigned int __stdcall SpkrThread(LPVOID Unused) { int i; DWORD bufLen = ((N_SAMPLES * BITS_PER_SAMPLE) / 8); WAVEHDR* pWH; MMRESULT ret; int played; OsMsg *pMsg = NULL; OsIntPtrMsg *pSpeakerMsg = NULL; BOOL bGotMsg ; int n; bool bDone ; static bool sLastRingerEnabled = false; OsStatus res; static bool bRunning = false ; HWAVEOUT hOut = NULL; UINT timerId=0; // Verify that only 1 instance of the MicThread is running if (bRunning) { ResumeThread(hMicThread); return 1 ; } else { bRunning = true ; } ResumeThread(hMicThread); #ifdef OHISTORY /* [ */ WAVEHDR* lastWH[OHISTORY]; int lastInd[OHISTORY]; int last = 0; for (i=0;i<OHISTORY;i++) { lastWH[i] = 0; lastInd[i] = 0; } memset(histOut, 0xff, sizeof(histOut)); lastOut = 0; #endif /* OHISTORY ] */ // Initialize headers for (i=0; i<N_OUT_BUFFERS; i++) { hOutHdr[i] = hOutBuf[i] = NULL; pOutHdr[i] = NULL; } if (openSpeakerDevices(pWH, hOut)) { // NOT using a sound card // Set up a 10ms timer to call back to this routine timerId = timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } played = 0; bDone = false ; while (!bDone) { bGotMsg = (gSpeakerStatusQueue->receive(pMsg) == OS_SUCCESS); // when switching devices, ringer to in-call we need to make // sure any outstanding buffers are flushed if (sLastRingerEnabled != DmaTask::isRingerEnabled()) { if (audioOutH) { ret = waveOutReset(audioOutH); } if (audioOutCallH) { ret = waveOutReset(audioOutCallH); } if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } else { waitForDeviceResetCompletion(); } } if (bGotMsg && pMsg) { pSpeakerMsg = (OsIntPtrMsg*)pMsg; intptr_t msgType = pSpeakerMsg->getData1(); intptr_t data2 = pSpeakerMsg->getData2(); pSpeakerMsg->releaseMsg(); pSpeakerMsg = NULL; pMsg = NULL; switch (msgType) { case WM_ALT_HEARTBEAT: OsSysLog::add(FAC_MP, PRI_DEBUG, "SpeakerThreadWnt invoking MpMediaTask::signalFrameStart from timer message"); res = MpMediaTask::signalFrameStart(); switch (res) { case OS_SUCCESS: frameCount++; break; #ifdef DEBUG_WINDOZE /* [ */ case OS_LIMIT_REACHED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_LIMIT_REACHED\n", frameCount); break; case OS_WAIT_TIMEOUT: // Should bump missed frame statistic osPrintf(" Frame %d: OS_WAIT_TIMEOUT\n", frameCount); break; case OS_ALREADY_SIGNALED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_ALREADY_SIGNALED\n", frameCount); break; default: osPrintf("Frame %d, signalFrameStart() returned %d\n", frameCount, res); break; #else /* DEBUG_WINDOZE ] [ */ case OS_LIMIT_REACHED: case OS_WAIT_TIMEOUT: case OS_ALREADY_SIGNALED: default: // Should bump missed frame statistic break; #endif /* DEBUG_WINDOZE ] */ } // Check for a changed speaker device if (DmaTask::isOutputDeviceChanged()) { DmaTask::clearOutputDeviceChanged() ; closeSpeakerDevices() ; if (audioOutH) { ret = waveOutReset(audioOutH); } if (audioOutCallH) { ret = waveOutReset(audioOutCallH); } if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } else { waitForDeviceResetCompletion(); } // Kill the hearbeat timer if it exists if (timerId>0) timeKillEvent(timerId); if (openSpeakerDevices(pWH, hOut)) { // Open failed - so start the heartbeat timer timerId = timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } continue ; } break ; case WOM_DONE: pWH = (WAVEHDR *) data2; n = (pWH->dwUser) & USER_BUFFER_MASK; #ifdef OHISTORY /* [ */ lastWH[last] = pWH; lastInd[last] = n; last = (last + 1) % OHISTORY; if (N_OUT_BUFFERS == played) { osPrintf("after first %d buffers:", played + 1); osPrintf("\nCall Backs:"); for (i=0; i<OHISTORY; i++) { osPrintf("%c%3d", (0 == (i % 20)) ? '\n' : ' ', histOut[i]); } osPrintf("\n\nMessages:"); for (i=0; i<OHISTORY; i++) { osPrintf("%c%3d", (0 == (i % 20)) ? '\n' : ' ', lastInd[i]); } osPrintf("\n"); } #endif /* OHISTORY ] */ if (DmaTask::isOutputDeviceChanged()) { DmaTask::clearOutputDeviceChanged() ; closeSpeakerDevices() ; if (openSpeakerDevices(pWH, hOut)) { if (timerId>0) timeKillEvent(timerId); timerId = timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } continue ; } hOut = selectSpeakerDevice() ; if (hOut) { ret = waveOutUnprepareHeader(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, played, __LINE__); } outPostUnprep(n, false); pWH = outPrePrep(n, bufLen); ret = waveOutPrepareHeader(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutPrepareHeader", ret, played, __LINE__); } ret = waveOutWrite(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutWrite", ret, played, __LINE__); } played++; } OsSysLog::add(FAC_MP, PRI_DEBUG, "SpeakerThreadWnt invoking MpMediaTask::signalFrameStart from WOM_DONE message"); res = MpMediaTask::signalFrameStart(); switch (res) { #ifdef DEBUG_WINDOZE /* [ */ case OS_SUCCESS: frameCount++; osPrintf(" Frame %d: OS_SUCCESSFUL\n", frameCount); break; case OS_LIMIT_REACHED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_LIMIT_REACHED\n", frameCount); break; case OS_WAIT_TIMEOUT: // Should bump missed frame statistic osPrintf(" Frame %d: OS_WAIT_TIMEOUT\n", frameCount); break; case OS_ALREADY_SIGNALED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_ALREADY_SIGNALED\n", frameCount); break; default: osPrintf("Frame %d, signalFrameStart() returned %d\n", frameCount, res); break; #else /* DEBUG_WINDOZE ] [ */ case OS_SUCCESS: frameCount++; break; case OS_LIMIT_REACHED: case OS_WAIT_TIMEOUT: case OS_ALREADY_SIGNALED: default: // Should bump missed frame statistic break; #endif /* DEBUG_WINDOZE ] */ } break; case WOM_CLOSE: // Audio device was closed on us (doesn't happen as far as I // know) bDone = true ; break; default: break; } } else { // Sky is falling, kick out so that we don't spin a high priority // thread. bDone = true ; } // record our last ringer state sLastRingerEnabled = DmaTask::isRingerEnabled(); } // Stop heartbeat timer if it exist if (timerId>0) timeKillEvent(timerId); closeSpeakerDevices() ; bRunning = false ; return 0; }
void closeSpeakerDevices() { MMRESULT ret; int i ; // Clean up ringer audio if (audioOutH) { ret = waveOutReset(audioOutH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } else { waitForDeviceResetCompletion(); } for (i=0; i<N_OUT_BUFFERS; i++) { if (NULL != hOutHdr[i]) { ret = waveOutUnprepareHeader(audioOutH, pOutHdr[i], sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, i, __LINE__); } outPostUnprep(i, TRUE); } } ret = waveOutClose(audioOutH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutClose", ret, -1, __LINE__); } audioOutH = NULL; waitForSpeakerStatusMessage(WOM_CLOSE); } // Clean up call audio if (audioOutCallH) { ret = waveOutReset(audioOutCallH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } else { waitForDeviceResetCompletion(); } for (i=0; i<N_OUT_BUFFERS; i++) { if (NULL != hOutHdr[i]) { ret = waveOutUnprepareHeader(audioOutCallH, pOutHdr[i], sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, i, __LINE__); } outPostUnprep(i, true); } } ret = waveOutClose(audioOutCallH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutClose", ret, -1, __LINE__); } audioOutCallH = NULL; waitForSpeakerStatusMessage(WOM_CLOSE); } }
static int openSpeakerDevices(WAVEHDR*& pWH, HWAVEOUT& hOut) { DWORD bufLen = ((N_SAMPLES * BITS_PER_SAMPLE) / 8); int i ; MMRESULT ret; // set the different device ids gRingDeviceId = WAVE_MAPPER; gCallDeviceId = WAVE_MAPPER; // If either the ringer or call device is set to NONE, don't engage any audio devices if ((strcasecmp(DmaTask::getRingDevice(), "NONE") == 0) || (strcasecmp(DmaTask::getCallDevice(), "NONE") == 0)) { ResumeThread(hMicThread); return 1; } /* * Select in-call / ringer devices */ int ii; WAVEOUTCAPS devcaps; int numberOfDevicesOnSystem = waveOutGetNumDevs(); for(ii=0; ii<numberOfDevicesOnSystem; ii++) { waveOutGetDevCaps(ii,&devcaps,sizeof(WAVEOUTCAPS)); if (strcmp(devcaps.szPname, DmaTask::getRingDevice())==0) { gRingDeviceId = ii; OsSysLog::add(FAC_MP, PRI_DEBUG, "SpkrThread: Selected ring device: %s\n",devcaps.szPname); } if (strcmp(devcaps.szPname, DmaTask::getCallDevice())==0) { gCallDeviceId = ii; OsSysLog::add(FAC_MP, PRI_DEBUG, "SpkrThread: Selected call device: %s\n",devcaps.szPname); } } /* * Open ringer device */ if (!openAudioOut(gRingDeviceId, &audioOutH, 1, SAMPLES_PER_SEC, BITS_PER_SAMPLE)) { OsSysLog::add(FAC_MP, PRI_DEBUG, "SpkrThread: Failed to open ring audio output channel\n\n"); ResumeThread(hMicThread); return 1; } waitForSpeakerStatusMessage(WOM_OPEN); /* * Open in-call device */ if (!openAudioOut(gCallDeviceId,&audioOutCallH, 1, SAMPLES_PER_SEC, BITS_PER_SAMPLE)) { OsSysLog::add(FAC_MP, PRI_DEBUG, "SpkrThread: Failed to open call audio output channel\n\n"); ResumeThread(hMicThread); return 1; } waitForSpeakerStatusMessage(WOM_OPEN); // Pre load some data for (i=0; i<smSpkrQPreload; i++) { pWH = outPrePrep(i, bufLen); hOut = selectSpeakerDevice() ; if (hOut) { ret = waveOutPrepareHeader(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutPrepareHeader", ret, i, __LINE__); } ret = waveOutWrite(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutWrite", ret, i, __LINE__); } } } return 0 ; }
void closeSpeakerDevices() { MMRESULT ret; int i ; MSG tMsg; BOOL bSuccess ; // Clean up ringer audio if (audioOutH) { ret = waveOutReset(audioOutH); Sleep(100) ; if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } for (i=0; i<N_OUT_BUFFERS; i++) { if (NULL != hOutHdr[i]) { ret = waveOutUnprepareHeader(audioOutH, pOutHdr[i], sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, i, __LINE__); } outPostUnprep(i, TRUE); } } ret = waveOutClose(audioOutH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutClose", ret, -1, __LINE__); } audioOutH = NULL; do { bSuccess = GetMessage(&tMsg, NULL, 0, 0) ; } while (bSuccess && (tMsg.message != WOM_CLOSE)) ; } // Clean up call audio if (audioOutCallH) { ret = waveOutReset(audioOutCallH); Sleep(100) ; if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutReset", ret, -1, __LINE__); } for (i=0; i<N_OUT_BUFFERS; i++) { if (NULL != hOutHdr[i]) { ret = waveOutUnprepareHeader(audioOutCallH, pOutHdr[i], sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, i, __LINE__); } outPostUnprep(i, true); } } ret = waveOutClose(audioOutCallH); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutClose", ret, -1, __LINE__); } audioOutCallH = NULL; do { bSuccess = GetMessage(&tMsg, NULL, 0, 0) ; } while (bSuccess && (tMsg.message != WOM_CLOSE)) ; } }
unsigned int __stdcall SpkrThread(LPVOID Unused) { int i; DWORD bufLen = ((N_SAMPLES * BITS_PER_SAMPLE) / 8); WAVEHDR* pWH; MMRESULT ret; int played; MSG tMsg; BOOL bGotMsg ; int n; bool bDone ; static bool sLastRingerEnabled = false; OsStatus res; static bool bRunning = false ; HWAVEOUT hOut = NULL; // Verify that only 1 instance of the MicThread is running if (bRunning) { ResumeThread(hMicThread); return 1 ; } else { bRunning = true ; } ResumeThread(hMicThread); #ifdef OHISTORY /* [ */ WAVEHDR* lastWH[OHISTORY]; int lastInd[OHISTORY]; int last = 0; for (i=0;i<OHISTORY;i++) { lastWH[i] = 0; lastInd[i] = 0; } memset(histOut, 0xff, sizeof(histOut)); lastOut = 0; #endif /* OHISTORY ] */ // Initialize headers for (i=0; i<N_OUT_BUFFERS; i++) { hOutHdr[i] = hOutBuf[i] = NULL; pOutHdr[i] = NULL; } if (openSpeakerDevices(pWH, hOut)) { // NOT using a sound card // Set up a 10ms timer to call back to this routine timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } played = 0; bDone = false ; while (!bDone) { bGotMsg = GetMessage(&tMsg, NULL, 0, 0); // when switching devices, ringer to in-call we need to make // sure any outstanding buffers are flushed if (sLastRingerEnabled != DmaTask::isRingerEnabled()) { if (audioOutH) { waveOutReset(audioOutH); } if (audioOutCallH) { waveOutReset(audioOutCallH); } } if (bGotMsg) { switch (tMsg.message) { case WM_ALT_HEARTBEAT: res = MpMediaTask::signalFrameStart(); switch (res) { case OS_SUCCESS: frameCount++; break; case OS_LIMIT_REACHED: case OS_WAIT_TIMEOUT: case OS_ALREADY_SIGNALED: default: // Should bump missed frame statistic break; } break ; case WOM_DONE: pWH = (WAVEHDR *) tMsg.wParam; n = (pWH->dwUser) & USER_BUFFER_MASK; #ifdef OHISTORY /* [ */ lastWH[last] = pWH; lastInd[last] = n; last = (last + 1) % OHISTORY; if (N_OUT_BUFFERS == played) { osPrintf("after first %d buffers:", played + 1); osPrintf("\nCall Backs:"); for (i=0; i<OHISTORY; i++) { osPrintf("%c%3d", (0 == (i % 20)) ? '\n' : ' ', histOut[i]); } osPrintf("\n\nMessages:"); for (i=0; i<OHISTORY; i++) { osPrintf("%c%3d", (0 == (i % 20)) ? '\n' : ' ', lastInd[i]); } osPrintf("\n"); } #endif /* OHISTORY ] */ if (DmaTask::isOutputDeviceChanged()) { DmaTask::clearOutputDeviceChanged() ; closeSpeakerDevices() ; if (openSpeakerDevices(pWH, hOut)) { timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } continue ; } hOut = selectSpeakerDevice() ; if (hOut) { ret = waveOutUnprepareHeader(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutUnprepareHeader", ret, played, __LINE__); } outPostUnprep(n, false); pWH = outPrePrep(n, bufLen); ret = waveOutPrepareHeader(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutPrepareHeader", ret, played, __LINE__); } ret = waveOutWrite(hOut, pWH, sizeof(WAVEHDR)); if (ret != MMSYSERR_NOERROR) { showWaveError("waveOutWrite", ret, played, __LINE__); /* RL < */ if (ret == MMSYSERR_NODRIVER) { closeSpeakerDevices() ; if (openSpeakerDevices(pWH, hOut)) { timeSetEvent(10, 0, TimerCallbackProc, GetCurrentThreadId(), TIME_PERIODIC); } continue; } /* RL > */ } played++; } res = MpMediaTask::signalFrameStart(); switch (res) { case OS_SUCCESS: frameCount++; break; #ifdef DEBUG_WINDOZE /* [ */ case OS_LIMIT_REACHED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_LIMIT_REACHED\n", frameCount); break; case OS_WAIT_TIMEOUT: // Should bump missed frame statistic osPrintf(" Frame %d: OS_WAIT_TIMEOUT\n", frameCount); break; case OS_ALREADY_SIGNALED: // Should bump missed frame statistic osPrintf(" Frame %d: OS_ALREADY_SIGNALED\n", frameCount); break; default: osPrintf("Frame %d, signalFrameStart() returned %d\n", frameCount, res); break; #else /* DEBUG_WINDOZE ] [ */ case OS_LIMIT_REACHED: case OS_WAIT_TIMEOUT: case OS_ALREADY_SIGNALED: default: // Should bump missed frame statistic break; #endif /* DEBUG_WINDOZE ] */ } break; case WOM_CLOSE: // Audio device was closed on us (doesn't happen as far as I // know) bDone = true ; break; default: break; } } else { // Sky is falling, kick out so that we don't spin a high priority // thread. bDone = true ; } // record our last ringer state sLastRingerEnabled = DmaTask::isRingerEnabled(); } closeSpeakerDevices() ; bRunning = false ; return 0; }