[源代碼以及工程實例下載 ]
1、 語音播放API
1.1 waveOutOpen - 打開播放設備
[cpp] view plaincopyprint?
MMRESULT?waveOutOpen(???????LPHWAVEOUT??????phwo,??????????????????????UINT_PTR????????uDeviceID,?????????????????LPWAVEFORMATEX??pwfx,??????????????????????DWORD_PTR???????dwCallback,???????????????DWORD_PTR???????dwCallbackInstance,????????DWORD???????????fdwOpen???????????????????);??
MMRESULT waveOutOpen( LPHWAVEOUT phwo, /* 一個指向接收波形音頻輸出設備的句柄 */ UINT_PTR uDeviceID, /* 將要被打開的波形音頻輸出設備的ID */ LPWAVEFORMATEX pwfx, /* 一個指向將被送到設備的音頻數據格式的WAVEFORMATEX結構的指針 */ DWORD_PTR dwCallback, /* 它指向一個特定的CALLBACK函數,事件柄,窗口柄... */DWORD_PTR dwCallbackInstance, /* 傳遞到CALLBACK進程的用戶實例數據,如是窗口,該參數設為0 */ DWORD fdwOpen /* 用來打開設備的標識(FLAGS) */);
??? 1)phwo:一個指向接收波形音頻輸出設備的句柄。用句柄來區別(identify)別的波形輸出設備。如果fdwOpen被設定為 WAVE_FORMAT_QUERY,那么這個參數可能為NULL 。
??? 2)uDevideID:將要被打開的波形音頻輸出設備的ID ,它可以是一個設備ID,也可以是一個已經打開的波形音頻輸入設備句柄,你可以用以下的值來貨替:
WAVE_MAPPER - 該函數選一個能夠播放給定格式的波形音頻輸出設備
??? 3)pwfx:一個指向將被送到設備的音頻數據格式的WAVEFORMATEX結構的指針,當調用waveOutOpen 函數之后可立即釋放該結構;
??? 4)dwCallback:它指向一個特定的CALLBACK函數,事件柄,窗口柄,或一個線程ID(用于在音頻回放時以便處理與回放進度相關的消息)。如果無須CALLBACK函數,可以將其設為0 。
??? 5)dwCallbackInstance :傳遞到CALLBACK進程的用戶實例數據。如果是窗口CALLBACK進程的話,該參數不用(設為0)
????6)fwOpen:用來打開設備的標識(FLAGS),它們的定義如下:
| 值 | 含義 |
| CALLBACK_EVENT | dwCallback 參數欄是事件句柄 |
| CALLBACK_FUNCTION | dwCallback 參數欄是CALLBACK函數地址 |
| CALLBACK_NULL | 默認的設置,即無CALLBACK進程 |
| CALLBACK_THREAD | dwCallback 參數欄是線程ID |
| CALLBACK_WINDOW | dwCallback 參數欄是窗口句柄 |
| WAVE_ALLOWSYNC | 如果該項被設置,一個同步的波形音頻設備能被打開。如果在打開一個同步驅動時沒有用該項,設備打開將會失敗。 |
| WAVE_FORMAT_DIRECT | 如果設定該項,音頻設備不會對輸出的音頻數據執行轉換 |
| WAVE_FORMAT_QUERY | 如果設定該項,waveOutOpen 用于詢問設備是否支持給定的格式,但設備實際上并沒有被打開。此時phwo參數可為NULL |
| WAVE_MAPPED | 該項被設定后uDeviceID參數表示將通過波形映射器映射到一個波形格式音頻設備。 |
??? 7)返回值:成功后返回MMSYSERR_NOERROR ,否則返回以下值:
| 值 | 描述 |
| MMSYSERR_ALLOCATED | 表示資源已存在 |
| MMSYSERR_BADDEVICEID | 設備ID超出范圍 |
| MMSYSERR_NODRIVER | 沒有驅動 |
| MMSYSERR_NOMEM | 不能分配內存 |
| WAVERR_BADFORMAT | 企圖打開一個不被支持的格式 |
| WAVERR_SYNC | 設備是可同步的,但waveOutOpen沒用有WAVE_ALLOWSYNC設置。 |
注:
??? waveoutopen創建設備實例句柄用于,使用其他waveoutAPI時將之作為參數,用于區別不同的音頻流。
??? 可用waveOutGetNumDevs函數測定在當前系統中輸出設備的數目。
??? 如果uDeviceID參數項是一個ID,它將會表示從0 到總的數目,WAAVE_MAPPER常量也可以用作裝置ID。
??? pwfc所指的結構能夠擴展到包含某些數據格式的特殊信息,例如,對于PCM數據,一個額外的UNIT類型用來表示取樣的位數目。在這個情況下用PCMWAVEFORAMT結構。對于其它的格式,用WAVEFORMATEX結構來表示額外的數據長度。
??? 如果你選用的是一個窗口或線程來接收CALLBACK信息,如下的信息將會被送到窗口處理函數中,來表明波形音頻輸出進程:MM_WOM_OPEN,MM_WOM_CLOSE ,和MM_WOM_DONE,如果你選用的是一個函數來接收CALLBACK信息,如下的信息將會被傳到函數中,來顯示波形音頻輸出進程:WOM_OPEN ,WOM_CLOSE,WOM_DONE。
1.2 waveOutPrepareHeader - 準備數據塊
[cpp] view plaincopyprint?
MMRESULT?waveOutPrepareHeader(??????HWAVEOUT?hwo,????????LPWAVEHDR?pwh,???????UINT?cbwh????????????);??備注:??
MMRESULT waveOutPrepareHeader(HWAVEOUT hwo, /* 波形音頻輸出設備的句柄 */LPWAVEHDR pwh, /* 一個WAVEHDR結構的指針,其基址必須與樣本大小對齊 */UINT cbwh /* WAVEHDR結構的大小,單位:字節 */);
備注:
[cpp] view plaincopyprint?
調用此函數之前必須設置WAVEHDR結構的lpData,dwBufferLength,dwFlags成員,dwFlags成員必須設置為0。??一旦準備完成,不可以修改lpData指針。??嘗試準備一個處于準備狀態的數據塊,將無效果,返回0??不應該在同一時刻為不同的波形設備準備同一個數據,如果想從一個設備錄制并在另一個設備播放數據,但不想拷貝緩存塊,可以分配兩塊WAVEHDR并將lpData指向同一數據緩存地址,其中一個調用<STRONG>waveInPrepareHeader</STRONG>,另一個調用<STRONG>waveOutPrepareHeader</STRONG>。??
調用此函數之前必須設置WAVEHDR結構的lpData,dwBufferLength,dwFlags成員,dwFlags成員必須設置為0。一旦準備完成,不可以修改lpData指針。嘗試準備一個處于準備狀態的數據塊,將無效果,返回0不應該在同一時刻為不同的波形設備準備同一個數據,如果想從一個設備錄制并在另一個設備播放數據,但不想拷貝緩存塊,可以分配兩塊WAVEHDR并將lpData指向同一數據緩存地址,其中一個調用<strong>waveInPrepareHeader</strong>,另一個調用<strong>waveOutPrepareHeader</strong>。
1.3 waveOutWrite - 將音頻數據塊送到指定的音頻輸出設備
[cpp] view plaincopyprint?
MMRESULT?waveOutWrite(??????HWAVEOUT?hwo,????? ??????LPWAVEHDR?pwh,? ??????UINT?cbwh? ?????????);???
MMRESULT waveOutWrite(HWAVEOUT hwo, /* 音頻輸出設備句柄 */ LPWAVEHDR pwh, /* 包含音頻數據塊信息的WAVEHDR結構指針 */ UINT cbwh /* WAVEHDR結構大小,單位byte */);
注意:
??? 要播放的數據一般在聲音文件里面獲得,并填入這個結構。由于是直接播放數據。所以要播放多少數據可以通過修改這個結構來達到目的。
??? 播放完數據后 WHDR_DONE 會設置到pwh指向的結構體中的dwFlags 成員
??? 在調用本函數之前必須調用waveOutPrepareHeader函數
??? 除非是恢復被waveOutPause函數暫停的設備,回調函數會在第一個數據塊一送達設備的時候就開始運作.回調函數在waveOutOpen里面設置
??? 請不要在回調函數里面調用任何的waveOut系列的函數,否則一定會造成死鎖。哪怕是waveOutUnprepareHeader,waveOutClose
1.4 waveOutUnprepareHeader - 清除音頻緩存數據
[cpp] view plaincopyprint?
MMRESULT?waveOutUnprepareHeader(????HWAVEOUT?hwo,?????LPWAVEHDR?pwh,?????UINT?cbwh???);??
MMRESULT waveOutUnprepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh
);
注意:
??? 調用時機,送到的音頻輸出設備的數據已經播放完成即:pwh的dwFlags中WHDR_DONE位有效
1.5 waveOutPause - 暫停音頻播放
1.6 waveOutRestart - 繼續播放已暫停的音頻設備
1.7 waveOutReset - 重設音頻輸出設備,將已準備好的緩存塊均設置為已播放完成
1.8 waveOutClose - 關閉音頻輸出設備
2、解碼器開發
[cpp] view plaincopyprint?
class?AMRFileDecoder??{??public:??????AMRFileDecoder(void);??????AMRFileDecoder(LPCTSTR?lpszFile);??????virtual?~AMRFileDecoder(void);????private:???????AMRFileDecoder(const?AMRFileDecoder&?)??????{??????????ATLASSERT(FALSE);??????}??????AMRFileDecoder&?operator=(const?AMRFileDecoder&)??????{??????????ATLASSERT(FALSE);??????????return?*this;??????}????public:????????????virtual?void?SetFilePathName(LPCTSTR?lpszFile);????????????virtual?ULONGLONG?GetTimeLength();????????????virtual?WAVEFORMATEX?GetWaveFromatX();????????????virtual?BOOL?BeginDecode();????????????virtual?DWORD?Decode(LPSTR&?pData);????????????virtual?bool?IsEOF();????????????virtual?void?EndDecode();????????????virtual?bool?IsVaild();????????????virtual?DWORD?GetDecodedMaxSize();????????????virtual?DWORD?GetDecodedFrameMaxSize();????private:??????DWORD?GetFrameCount();????private:??????LPSTR???????m_pBaseAddress;???????????????LONGLONG????m_liFileSize;?????????????????ULONG???????m_dwFrameCount;???????????????LPSTR???????m_pCurAddress;????????????????LPVOID??????m_pvDecoderState;?????????????CString?????m_sFilePathName;??????????};??
class AMRFileDecoder
{
public:AMRFileDecoder(void);AMRFileDecoder(LPCTSTR lpszFile);virtual ~AMRFileDecoder(void);private: // 屏蔽拷貝構造函數和賦值運算AMRFileDecoder(const AMRFileDecoder& ){ATLASSERT(FALSE);}AMRFileDecoder& operator=(const AMRFileDecoder&){ATLASSERT(FALSE);return *this;}public:/// 設置需解碼文件路徑virtual void SetFilePathName(LPCTSTR lpszFile);/// 獲取總時間長度,單位msvirtual ULONGLONG GetTimeLength();/// 獲取解碼后的波形格式virtual WAVEFORMATEX GetWaveFromatX();/// 開始解碼,初始化解碼器virtual BOOL BeginDecode();/// 解碼,每解碼一幀,游標后移至下一幀,返回解碼后的幀大小,輸出解碼后的波形數據virtual DWORD Decode(LPSTR& pData);/// 判斷是否解碼結束virtual bool IsEOF();/// 結束解碼,銷毀解碼器virtual void EndDecode();/// 判斷解碼器是否正常virtual bool IsVaild();/// 獲取解碼后的波形數據大小,單位bytevirtual DWORD GetDecodedMaxSize();/// 獲取解碼后的波形數據幀大小,單位bytevirtual DWORD GetDecodedFrameMaxSize();private:DWORD GetFrameCount();private:LPSTR m_pBaseAddress; // 文件映射內存塊首地址LONGLONG m_liFileSize; // 文件映射內存塊大小ULONG m_dwFrameCount; // 幀總數LPSTR m_pCurAddress; // 解碼游標,指示當前解碼位置LPVOID m_pvDecoderState; // 解碼器狀態指針CString m_sFilePathName; // 解碼文件路徑
};
3、解碼線程
[cpp] view plaincopyprint?
if(m_pDecoder?==?NULL?||?!m_pDecoder->IsVaild())??????????return?0;??????????????if(!m_pDecoder->BeginDecode())??????{??????????return?0;??????}??????????????DWORD?dwFrameMaxSize?=?m_pDecoder->GetDecodedFrameMaxSize();??????LPSTR?pBufferBase?=?(LPSTR)malloc(dwFrameMaxSize);??????ATLASSERT(pBufferBase);??????memset(pBufferBase,?0,?dwFrameMaxSize);??????if(pBufferBase?==?NULL)?return?0;????????register?ThreadMsg?tmsg?=?TMSG_ALIVE;????????DWORD?dwSizeAmount?=?0;??????while(!m_pDecoder->IsEOF()?&&?tmsg)??????{????????????????????DWORD?dwSize?=?m_pDecoder->Decode(pBufferBase);??????????dwSizeAmount?+=?dwSize;??????????????????????EnterCriticalSection(&m_cs);?????????????????????memcpy(m_waveData.pData?+?m_waveData.dwSize,?pBufferBase,?dwSize);??????????m_waveData.dwSize?+=?dwSize;??????????LeaveCriticalSection(&m_cs);??????????????????????if(dwSizeAmount?>?BLOCK_SIZE)??????????{??????????????dwSizeAmount?=?0;??????????????SetEvent(m_hEventDecode);??????????}??????????????????????Sleep(1);??????????????????????EnterCriticalSection(&m_cs);??????????tmsg?=?m_msgDecodeThread;??????????LeaveCriticalSection(&m_cs);??????}??????????????if(dwSizeAmount?>?0)??????{??????????SetEvent(m_hEventDecode);??????}????????m_waveData.bDecodeFinished?=?true;??????????????m_pDecoder->EndDecode();????????free(pBufferBase);??????pBufferBase?=?NULL;????????return?0;??}??
if(m_pDecoder == NULL || !m_pDecoder->IsVaild())return 0;// 開始解碼,初始化解碼器if(!m_pDecoder->BeginDecode()){return 0;}// 申請臨時內存塊,存儲解碼后的波形數據DWORD dwFrameMaxSize = m_pDecoder->GetDecodedFrameMaxSize();LPSTR pBufferBase = (LPSTR)malloc(dwFrameMaxSize);ATLASSERT(pBufferBase);memset(pBufferBase, 0, dwFrameMaxSize);if(pBufferBase == NULL) return 0;register ThreadMsg tmsg = TMSG_ALIVE;DWORD dwSizeAmount = 0;while(!m_pDecoder->IsEOF() && tmsg){// 解碼,每幀DWORD dwSize = m_pDecoder->Decode(pBufferBase);dwSizeAmount += dwSize;// 將解碼后數據寫入緩存區,供播放線程使用EnterCriticalSection(&m_cs); memcpy(m_waveData.pData + m_waveData.dwSize, pBufferBase, dwSize);m_waveData.dwSize += dwSize;LeaveCriticalSection(&m_cs);// 當解碼數據量操作了一個播放緩存時,發個信號,通知可以開始播放了if(dwSizeAmount > BLOCK_SIZE){dwSizeAmount = 0;SetEvent(m_hEventDecode);}// 節省CPU時間,讓CPU有時間去干別的事兒Sleep(1);// 檢測線程是否將被強制退出EnterCriticalSection(&m_cs);tmsg = m_msgDecodeThread;LeaveCriticalSection(&m_cs);}// 如果數據量很小,根本不足一個播放緩存,也要發個信號if(dwSizeAmount > 0){SetEvent(m_hEventDecode);}m_waveData.bDecodeFinished = true;// 解碼結束m_pDecoder->EndDecode();free(pBufferBase);pBufferBase = NULL;return 0;
}
4、播放線程
[cpp] view plaincopyprint?
unsigned?int?WavePlayer::PlayThreadProcImpl()??{????????????register????ThreadMsg???????tmsg??=?TMSG_ALIVE;???????????????????????while(?tmsg?)??????{????????????????????Sleep(10);??????????????????????EnterCriticalSection(?&m_cs?);??????????tmsg?=?m_msgPlayThread;??????????LeaveCriticalSection(?&m_cs?);????????????????????if(!tmsg)???break;??????????????????????if(m_hWaveoutDev?==?NULL)??????????{??????????????EnterCriticalSection(&m_cs);??????????????MMRESULT?mmres?=?waveOutOpen(&m_hWaveoutDev,?WAVE_MAPPER,?&m_waveData.wfmtx,?(DWORD_PTR)WaveOutProc,?(DWORD_PTR)this,?CALLBACK_FUNCTION);??????????????LeaveCriticalSection(&m_cs);??????????????if(mmres?!=?MMSYSERR_NOERROR)??????????????{????????????????????????????????????continue;??????????????}??????????}??????????????????????????????EnterCriticalSection(?&m_cs?);??????????int?free?=?m_wBlock.wfreeblock;??????????LeaveCriticalSection(?&m_cs?);???????????? ??????????if(free?<?BP_TURN)??????????{??????????????continue;??????????}????????????????????????????????????????????????????????????????WAVEHDR?????*current?=?NULL;??????????????????????for(?unsigned?int?m?=?0;?m?<?BP_TURN;?m++?)??????????{???????????????????????????????current?=?&m_wBlock.pWaveHdr[m_wBlock.wcurrblock];???????????????????????????????if(?current->dwFlags?&?WHDR_PREPARED?)??????????????{??????????????????waveOutUnprepareHeader(?m_hWaveoutDev,?current,?sizeof(WAVEHDR)?);??????????????}???????????????? ??????????????EnterCriticalSection(&m_cs);??????????????unsigned?long?left??=?m_waveData.dwSize?-?m_wBlock.wpos;??????????????unsigned?int?bDecodeFinished?=?m_waveData.bDecodeFinished;??????????????LeaveCriticalSection(&m_cs);??????????????unsigned?long?chunk?=?0;????????????????if(?left??>=?BLOCK_SIZE?)??????????????{??????????????????chunk??=?BLOCK_SIZE;??????????????}??????????????else?if(!bDecodeFinished)??????????????{????????????????????????????????????break;??????????????}??????????????else?if(?left?&&?left?<?BLOCK_SIZE)??????????????{??????????????????chunk??=?left;??????????????}??????????????else??????????????{????????????????????????????????????????????????????????????????????????????? ??????????????????EnterCriticalSection(?&m_cs?);??????????????????int?free?=?m_wBlock.wfreeblock;??????????????????LeaveCriticalSection(?&m_cs?);??????????????????????????????????????if(?free?==?BLOCK_COUNT?)??????????????????{????????????????????????????????????????????for(?int?j?=?0;?j?<?m_wBlock.wfreeblock;?j++)???????????????????????{??????????????????????????if(?m_wBlock.pWaveHdr[j].dwFlags?&?WHDR_PREPARED?)??????????????????????????{??????????????????????????????waveOutUnprepareHeader(m_hWaveoutDev,?&m_wBlock.pWaveHdr[j],?sizeof(WAVEHDR));??????????????????????????}??????????????????????}???????????????????????? ??????????????????????tmsg?=?TMSG_CLOSE;????????????????????????????????????????????OnPlayFinished();??????????????????}???????????????????? ??????????????????break;??????????????}??????????????????????????????EnterCriticalSection(&m_cs);??????????????memcpy(?current->lpData,?&m_waveData.pData[m_wBlock.wpos],?chunk?);??????????????LeaveCriticalSection(&m_cs);????????????????current->dwBufferLength??=?chunk;?????????????????m_wBlock.wpos???????????+=?chunk;??????????????????? ??????????????waveOutPrepareHeader(?m_hWaveoutDev,?current,?sizeof(WAVEHDR)?);??????????????????????????????waveOutWrite(m_hWaveoutDev,?current,?sizeof(WAVEHDR));??????????????????????????????EnterCriticalSection(?&m_cs?);??????????????m_wBlock.wfreeblock--;??????????????LeaveCriticalSection(?&m_cs?);???????????????? ??????????????m_wBlock.wcurrblock++;??????????????m_wBlock.wcurrblock?%=?BLOCK_COUNT;??????????}????????}????????????????????????????????????????????if(m_hWaveoutDev)??????{??????????waveOutReset(?m_hWaveoutDev?);??????????????????????for(?int?j?=?0;?j?<?BLOCK_COUNT;?j++)???????????{??????????????if(?m_wBlock.pWaveHdr[j].dwFlags?&?WHDR_PREPARED?)??????????????{??????????????????waveOutUnprepareHeader(m_hWaveoutDev,?&m_wBlock.pWaveHdr[j],?sizeof(WAVEHDR));??????????????}??????????}????????????waveOutClose(m_hWaveoutDev);??????????m_hWaveoutDev?=?NULL;??????}????????return?THREAD_EXIT;??}??
unsigned int WavePlayer::PlayThreadProcImpl()
{/// 定義為寄存器變量,因為它將會被高頻率的使用,用于編譯器優化register ThreadMsg tmsg = TMSG_ALIVE; /// 線程循環while( tmsg ){// 每次循環后,交出CPU控制權,放在此處,因為下面有continue語句Sleep(10);/// 首先檢查線程消息EnterCriticalSection( &m_cs );tmsg = m_msgPlayThread;LeaveCriticalSection( &m_cs );// 線程要結束,退出線程循環if(!tmsg) break;// 如果設備為空,表示還沒有打開設備,需要打開設備if(m_hWaveoutDev == NULL){EnterCriticalSection(&m_cs);MMRESULT mmres = waveOutOpen(&m_hWaveoutDev, WAVE_MAPPER, &m_waveData.wfmtx, (DWORD_PTR)WaveOutProc, (DWORD_PTR)this, CALLBACK_FUNCTION);LeaveCriticalSection(&m_cs);if(mmres != MMSYSERR_NOERROR){// failed, try again.continue;}}// 檢查空閑緩存塊EnterCriticalSection( &m_cs );int free = m_wBlock.wfreeblock;LeaveCriticalSection( &m_cs );// 如果沒有空閑的緩存了,等待...if(free < BP_TURN){continue;}///// < 播放主循環 > /////WAVEHDR *current = NULL;/// BP_TURN為每次寫入播放隊列的塊數for( unsigned int m = 0; m < BP_TURN; m++ ){ /// 當前空閑播放緩存塊current = &m_wBlock.pWaveHdr[m_wBlock.wcurrblock]; // 首先需要檢查有沒有被Unprepare掉if( current->dwFlags & WHDR_PREPARED ){waveOutUnprepareHeader( m_hWaveoutDev, current, sizeof(WAVEHDR) );}/// 計算剩余需要播放的數據EnterCriticalSection(&m_cs);unsigned long left = m_waveData.dwSize - m_wBlock.wpos;unsigned int bDecodeFinished = m_waveData.bDecodeFinished;LeaveCriticalSection(&m_cs);unsigned long chunk = 0;if( left >= BLOCK_SIZE ){chunk = BLOCK_SIZE;}else if(!bDecodeFinished){// 如果解碼還沒有結束,現有的數據量有不足以填滿一個緩存塊,先不寫入緩存break;}else if( left && left < BLOCK_SIZE){chunk = left;}else{ ///// < 播放完成> //////// 獲取空閑緩存塊數量EnterCriticalSection( &m_cs );int free = m_wBlock.wfreeblock;LeaveCriticalSection( &m_cs );/// 當所有的緩存塊都播放完了,才意味著播放真正完成if( free == BLOCK_COUNT ){/// Unprepare緩存塊for( int j = 0; j < m_wBlock.wfreeblock; j++) {if( m_wBlock.pWaveHdr[j].dwFlags & WHDR_PREPARED ){waveOutUnprepareHeader(m_hWaveoutDev, &m_wBlock.pWaveHdr[j], sizeof(WAVEHDR));}}// 此時,才算真正的播放完成,關閉線程tmsg = TMSG_CLOSE;// 處理播放完成事件OnPlayFinished();}// 此break僅跳出該循環,沒有跳出線程循環break;}/// prepare current wave data block headerEnterCriticalSection(&m_cs);memcpy( current->lpData, &m_waveData.pData[m_wBlock.wpos], chunk );LeaveCriticalSection(&m_cs);current->dwBufferLength = chunk; // sizeof blockm_wBlock.wpos += chunk; // update position/// prepare for playbackwaveOutPrepareHeader( m_hWaveoutDev, current, sizeof(WAVEHDR) );/// push to the queuewaveOutWrite(m_hWaveoutDev, current, sizeof(WAVEHDR));/// 減小空閑塊計數EnterCriticalSection( &m_cs );m_wBlock.wfreeblock--;LeaveCriticalSection( &m_cs );/// 使當前空閑塊指向下一個m_wBlock.wcurrblock++;m_wBlock.wcurrblock %= BLOCK_COUNT;}}/// thread//////////// < force to close device which are still playing > //////if(m_hWaveoutDev){waveOutReset( m_hWaveoutDev );/// unprepare any blocks that are still preparedfor( int j = 0; j < BLOCK_COUNT; j++) {if( m_wBlock.pWaveHdr[j].dwFlags & WHDR_PREPARED ){waveOutUnprepareHeader(m_hWaveoutDev, &m_wBlock.pWaveHdr[j], sizeof(WAVEHDR));}}waveOutClose(m_hWaveoutDev);m_hWaveoutDev = NULL;}return THREAD_EXIT;
}
5、主播放線程
[cpp] view plaincopyprint?
??????if(m_ePlayStat?!=?Play_Stop)??????{??????????Stop();??????}??????????????if(m_pDecoder?==?NULL)??????{??????????m_pDecoder?=?new?AMRFileDecoder(lpszFile);??????}??????else??????{??????????m_pDecoder->SetFilePathName(lpszFile);??????}??????????????if(pLength)??????{??????????*pLength?=?(DWORD)m_pDecoder->GetTimeLength();??????}??????????????DWORD?dwWaveMaxSize?=?m_pDecoder->GetDecodedMaxSize();??????EnterCriticalSection(&m_cs);??????m_waveData.wfmtx?=?m_pDecoder->GetWaveFromatX();??????m_waveData.pData?=?(LPSTR)HeapAlloc(GetProcessHeap(),?HEAP_ZERO_MEMORY,?dwWaveMaxSize);??????LeaveCriticalSection(&m_cs);??????????????????????if(m_hThreadDecode?==?NULL)??????{??????????m_msgDecodeThread?=?TMSG_ALIVE;??????????m_hThreadDecode?=?CreateThread(NULL,?0,?(LPTHREAD_START_ROUTINE)DecodeThread,?(LPVOID)this,?CREATE_SUSPENDED,?NULL);??????????ATLASSERT(m_hThreadDecode);??????????ResumeThread(m_hThreadDecode);??????}??????????????WaitForSingleObject(m_hEventDecode,?INFINITE);??????????????if(m_hThreadPlay?==?NULL)??????{??????????m_msgPlayThread?=?TMSG_ALIVE;??????????m_hThreadPlay?=?CreateThread(?NULL,?0,?(LPTHREAD_START_ROUTINE)PlayThread,?(LPVOID)this,?CREATE_SUSPENDED,?NULL?);??????????ATLASSERT(m_hThreadPlay);??????????ResumeThread(m_hThreadPlay);??????}????????m_ePlayStat?=?Play_Playing;
總結
以上是生活随笔為你收集整理的多线程应用---使用WaveOut* API开发AMR音频播放器(含源码下载)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。