📄 winaudio.cpp
字号:
default: theErr = HXR_OUTOFMEMORY; break; }#if defined(_WIN32) && !defined(_WINCE) if ( !theErr ) { if (!zm_bMixerVolSupportChecked) { CheckForVolumeSupport(); } }#endif return theErr;}HX_RESULT CAudioOutWindows::_Imp_Close(){#ifdef _TESTING if ( m_audfile > 0 ) close(m_audfile); m_audfile = -1;#endif zm_bClosed = TRUE; if (m_hWave) { // NOTE: Before we can close, we need to reset! Reset(); m_pMutex->Lock(); if (m_pWaveHdrs) { UINT16 unWHIndex; // Unprepare the individual headers for (unWHIndex = 0; unWHIndex < m_unAllocedBufferCnt; ++unWHIndex) { CWaveHeader* pWaveHeader = &m_pWaveHdrs[unWHIndex]; if (pWaveHeader->m_pPrepared) { LPWAVEHDR lpwHeader = LPWAVEHDR(&pWaveHeader->m_WAVEHDR); // By now all headers should be marked as done because they // are back from the audio device or prepared because we // prepared them but never used them HX_ASSERT(lpwHeader->dwFlags & WHDR_DONE || lpwHeader->dwFlags & WHDR_PREPARED); //OutputDebugString("BEFORE CALL TO:waveOutUnprepareHeader\r\n"); HX_VERIFY(MMSYSERR_NOERROR == waveOutUnprepareHeader(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR))); //OutputDebugString("AFTER CALL TO:waveOutUnprepareHeader\r\n"); pWaveHeader->m_pPrepared = FALSE; } } } if (m_ppAllocedBuffers) { UINT16 unIndex; for (unIndex = 0; unIndex < m_unAllocedBufferCnt; unIndex++) { delete[] m_ppAllocedBuffers[unIndex]; } delete[] m_ppAllocedBuffers; m_ppAllocedBuffers = NULL; } m_rAvailBuffers.FlushQueue(); m_UsedBuffersList.RemoveAll(); m_unAllocedBufferCnt = 0; m_pMutex->Unlock(); for (int i = 0; i < 5 && (WAVERR_STILLPLAYING == waveOutClose( m_hWave )); ++i) { waveOutReset( m_hWave ); } m_hWave = NULL; if (m_pWaveHdrs) { delete[] m_pWaveHdrs; m_pWaveHdrs = NULL; } } UnRegister(); m_bIsFirstPacket = TRUE; m_bInitialized = FALSE; return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Write( const HXAudioData* pAudioOutHdr ){ BOOL bTemp; CWaveHeader* pWaveHeader; MMRESULT res; ULONG32 ulBufLen = 0; UCHAR* pBuffer = 0; if (pAudioOutHdr->pData) { pBuffer = pAudioOutHdr->pData->GetBuffer(); ulBufLen = pAudioOutHdr->pData->GetSize(); } if (!m_bInitialized) { m_bInitialized = AllocateBuffers(MAX_REASONABLE_BUFFS,(UINT16)ulBufLen); } if (!m_bInitialized) return HXR_FAILED; m_pMutex->Lock(); pWaveHeader = (CWaveHeader*)m_rAvailBuffers.DeQueuePtr(bTemp); m_pMutex->Unlock(); if (!bTemp) { return HXR_WOULD_BLOCK; }#ifdef _TESTING if ( m_audfile > 0 ) write(m_audfile, pBuffer,ulBufLen); #endif UINT32 ulBytesToCopy = ulBufLen; HX_ASSERT(ulBytesToCopy <= pWaveHeader->m_WAVEHDR.dwBufferLength); if (ulBytesToCopy > pWaveHeader->m_WAVEHDR.dwBufferLength) ulBytesToCopy = pWaveHeader->m_WAVEHDR.dwBufferLength; pWaveHeader->m_bAvail = FALSE; memcpy(pWaveHeader->m_WAVEHDR.lpData, pBuffer, HX_SAFESIZE_T(ulBytesToCopy)); /* Flawfinder: ignore */ pWaveHeader->m_ulTimeEnd = pAudioOutHdr->ulAudioTime; /* This is needed for LIVE where audio packets may not start * from timestamp 0 */ if (m_bIsFirstPacket) { m_bIsFirstPacket = FALSE; } //OutputDebugString("BEFORE CALL TO:waveOutWrite\r\n"); res = waveOutWrite(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR)); m_pMutex->Lock(); m_UsedBuffersList.AddTail(pWaveHeader); m_pMutex->Unlock(); //OutputDebugString("AFTER CALL TO:waveOutWrite\r\n"); return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Seek(ULONG32 ulSeekTime){ return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Pause(){ MMRESULT res; if (m_hWave) {// OutputDebugString("BEFORE CALL TO:waveOutPause\r\n"); res = waveOutPause(m_hWave); //OutputDebugString("AFTER CALL TO:waveOutPause\r\n"); } return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Resume(){ MMRESULT res; if (m_hWave) {// OutputDebugString("BEFORE CALL TO:waveOutRestart\r\n"); res = waveOutRestart(m_hWave); //OutputDebugString("AFTER CALL TO:waveOutRestart\r\n"); } OnTimeSync(); return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Reset(){//{FILE* f1 = ::fopen("c:\\audio.txt", "a+"); ::fprintf(f1, "Reset: \n");::fclose(f1);} MMRESULT res; m_bResetting = TRUE; if (m_hWave) {// OutputDebugString("BEFORE CALL TO:waveOutReset\r\n"); res = waveOutReset(m_hWave); // Need to be turned on after RC2000 XXXRA // commenting it out for safety reasons. //_Imp_Pause(); //OutputDebugString("AFTER CALL TO:waveOutReset\r\n"); m_bIsFirstPacket = TRUE; m_llDeviceBytesPlayed = 0; m_llDeviceSamplesPlayed = 0; m_ulLastDeviceBytesPlayed = 0; m_ulLastDeviceSamplesPlayed = 0; m_ulDevPosRollOver = 0; } // First return the unused buffers to the available queue // Then pump out the wom_dones. // _NumberOfBlocksRemainingToPlay(); // Make sure we handle all the wave-done messages, // but establish a time limit to cope with the // unpredictable nature of Windows. Wait for up // to 1 second. DWORD start = HX_GET_TICKCOUNT(); if (m_hWnd) { do { MSG msg; // Yield, and try to pump WOM_DONE's to the Async Window! while (PeekMessage(&msg, m_hWnd, MM_WOM_DONE, MM_WOM_DONE, PM_REMOVE)) { if(msg.message == WM_QUIT) { // When peeking WM_QUIT message in the main thread of an application // we have to put it back into message queue to allow the application // to exit correctly. SB PostQuitMessage(0); break; } else { DispatchMessage(&msg); } } if (CALCULATE_ELAPSED_TICKS(start, HX_GET_TICKCOUNT()) >= 1000) { // Brute force, mark them as free... We probably // could do something better here, like close and // reopen the wave device... but this is what the // old code did, so lets try it as well! ULONG32 lTmp; m_pMutex->Lock(); for (lTmp = 0; m_pWaveHdrs && (lTmp < m_unAllocedBufferCnt); ++lTmp) { CWaveHeader *pwhDone = &m_pWaveHdrs[lTmp]; if (pwhDone && pwhDone->m_bAvail == FALSE) { pwhDone->m_bAvail = TRUE; m_rAvailBuffers.EnQueuePtr(pwhDone); } } m_pMutex->Unlock(); //OutputDebugString("Bail WOM_DONE vacuum, passed timeout!\r\n"); break; } } while (_NumberOfBlocksRemainingToPlay()); } //OutputDebugString("END: WOM_DONE vacuum!\r\n"); m_bResetting = FALSE; return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_Drain(){ return HXR_OK;}HX_RESULT CAudioOutWindows::_Imp_CheckFormat( const HXAudioFormat* pFormat ){#if defined(_WIN32) LPWAVEFORMATEX wavePtr;#elif defined( _WINDOWS ) LPWAVEFORMAT wavePtr;#endif m_WaveFormat.SetFormat(pFormat->ulSamplesPerSec, pFormat->uChannels, pFormat->uBitsPerSample); // Get the Windows style wave format! wavePtr = m_WaveFormat.GetWaveFormat(); MMRESULT wRet = waveOutOpen(&m_hWave,WAVE_MAPPER,wavePtr, 0, (DWORD)this,WAVE_FORMAT_QUERY); switch (wRet) { case MMSYSERR_NOERROR: return( HXR_OK ); case MMSYSERR_ALLOCATED: return( HXR_AUDIO_DRIVER ); case MMSYSERR_NOMEM: return( HXR_OUTOFMEMORY ); case MMSYSERR_BADDEVICEID: return( HXR_AUDIO_DRIVER ); case WAVERR_BADFORMAT: return( HXR_AUDIO_DRIVER ); case WAVERR_SYNC: return( HXR_AUDIO_DRIVER ); case MMSYSERR_NODRIVER: return( HXR_AUDIO_DRIVER ); default: return( HXR_AUDIO_DRIVER ); }}BOOL CAudioOutWindows::AllocateBuffers(UINT16 unNumBuffers, UINT16 unBufSize){ UCHAR** ppWaveBuffers; CWaveHeader* pWaveHdrs; MMRESULT tRes; UINT16 unWHIndex; ppWaveBuffers = NULL; pWaveHdrs = NULL; // Allocate memory for wave block headers and for wave data. if (!(pWaveHdrs = new CWaveHeader [unNumBuffers])) { goto OnError; } // This array holds the buffer pointers so we can free them later // There NO other purpose for this array. if (!(ppWaveBuffers = new UCHAR*[unNumBuffers])) { goto OnError; } memset( ppWaveBuffers, 0, unNumBuffers * sizeof( UCHAR* ) ); // Mark all wave block headers as available, and point them // at their respective wave data blocks. // AND enqueue them in the AvailableBuffers Queue. // AND allocate their buffers!!! for (unWHIndex = 0; unWHIndex < unNumBuffers; unWHIndex++) { UCHAR* pBuff; // Try to allocate the individual audio buffers pBuff = new UCHAR [unBufSize]; if (!pBuff) { goto OnError; } ppWaveBuffers[unWHIndex] = pBuff; CWaveHeader* pWaveHeader = &pWaveHdrs[unWHIndex]; // Init some header data before Preparing the header pWaveHeader->m_WAVEHDR.lpData = (char *)pBuff; pWaveHeader->m_WAVEHDR.dwUser = DWORD(pWaveHeader); pWaveHeader->m_WAVEHDR.dwFlags = 0L; pWaveHeader->m_WAVEHDR.dwBufferLength = unBufSize; pWaveHeader->m_WAVEHDR.dwLoops = 0L; pWaveHeader->m_bAvail = TRUE; pWaveHeader->m_pUser = this; m_pMutex->Lock(); m_rAvailBuffers.EnQueuePtr(pWaveHeader); m_pMutex->Unlock(); //OutputDebugString("BEFORE CALL TO:waveOutPrepareHeader\r\n"); tRes = waveOutPrepareHeader(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR)); //OutputDebugString("AFTER CALL TO:waveOutPrepareHeader\r\n"); if (tRes != MMSYSERR_NOERROR) { goto OnError; } else { pWaveHeader->m_pPrepared = TRUE; } } m_unAllocedBufferCnt = unNumBuffers; m_unAllocedBuffSize = unBufSize; m_pWaveHdrs = pWaveHdrs; m_ppAllocedBuffers = ppWaveBuffers; return TRUE;OnError: if (pWaveHdrs) { // Unprepare the individual headers for (unWHIndex = 0; unWHIndex < unNumBuffers; ++unWHIndex) { CWaveHeader* pWaveHeader = &pWaveHdrs[unWHIndex]; if (pWaveHeader->m_pPrepared) { //OutputDebugString("BEFORE CALL TO:waveOutUnprepareHeader\r\n"); tRes = waveOutUnprepareHeader(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR)); //OutputDebugString("AFTER CALL TO:waveOutUnprepareHeader\r\n"); pWaveHeader->m_pPrepared = FALSE; } } delete[] pWaveHdrs; pWaveHdrs = NULL; } // ppWaveBuffers actually points at an array of pointers that need to be free'd if (ppWaveBuffers) { // Free the individual buffers for (unWHIndex = 0; unWHIndex < unNumBuffers; ++unWHIndex) { UCHAR* pBuff; pBuff = ppWaveBuffers[unWHIndex]; if (pBuff) { delete[] pBuff; } } // Now free ppWaveBuffers itself delete[] ppWaveBuffers; ppWaveBuffers = NULL; } return FALSE;}/************************************************************************ * Method: * CAudioOutWindows::_Imp_GetCurrentTime * Purpose: * Get the current time from the audio device. * We added this to support the clock available in the * Window's audio driver. */HX_RESULT CAudioOutWindows::_Imp_GetCurrentTime( ULONG32& ulCurrentTime){ ULONG32 ulDeviceTime = 0; ULONG32 ulDeviceBytesPlayed = 0; UINT32 ulDeviceSamplesPlayed = 0; WAVEFMTPTR pWFmt = m_WaveFormat.GetWaveFormat(); // Set the time to the playback time of the // wave device since it's the most accurate. MMTIME mmTime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -