日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

waveout系列API实现pcm音频播放

發(fā)布時(shí)間:2024/1/3 综合教程 37 生活家
生活随笔 收集整理的這篇文章主要介紹了 waveout系列API实现pcm音频播放 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

最近做一個(gè)播放組件,也算是折騰1周了,收獲還算不少。

回想下整個(gè)編碼過程中磕磕碰碰走了不少彎路,最大的杯具就是,太相信網(wǎng)上現(xiàn)有代碼例子。

國內(nèi)網(wǎng)上關(guān)于waveout的文章不少,但基本就那幾篇轉(zhuǎn)載,其中的問題也沒有人指出。

為了方便大家用到時(shí)少被誤導(dǎo),在此留下我的筆記(如果被我誤導(dǎo)了,我先道歉-,-)

代碼不多,直接上關(guān)鍵部分(本人認(rèn)為多余代碼貼上去百害而無一利):

一、初始化設(shè)備

bool WinAudioPlay::DevOpen()
{
    if (!m_bPalyStata)
    {
        WAVEFORMATEX    wfx;
        ZeroMemory(&wfx,sizeof(WAVEFORMATEX));
    
        wfx.wFormatTag = WAVE_FORMAT_PCM;
        wfx.nChannels = 2;
        wfx.nSamplesPerSec = 44100L;
        wfx.wBitsPerSample = 16;
        wfx.cbSize = 0;
        wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;    
        wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * wfx.wBitsPerSample / 8;
    
        if(::waveOutOpen (0,0,&wfx,0,0,WAVE_FORMAT_QUERY))
        {
            Plug::PlugMessageBox(L"wave設(shè)備初始化失敗~");
            return false;
        }
        if (::waveOutOpen(&m_hWaveOut, WAVE_MAPPER, &wfx, (DWORD)&WinAudioPlay::waveOutProc, (DWORD)this, CALLBACK_FUNCTION))
        {
            Plug::PlugMessageBox(L"wave設(shè)備初始化失敗~");
            return false;
        }
        m_iBlockNum        = 0;
        m_bPalyStata    = true;
        m_spbrTgthr.reset(new boost::barrier(2));
        m_sptrdWaveOutTgthr.reset(new boost::thread(boost::bind(&WinAudioPlay::ThrdWaveOutTogether,this)));
    } 
    return true;
}

二、接收pcm格式數(shù)據(jù),并加載到聲卡緩沖區(qū)

bool __stdcall WinAudioPlay::play_audio( const void* buffer, int len )
{
    if (!m_bPalyStata)
        return false;

    if (BLOCK_MAX <= m_iBlockNum || len <= 0)
    {
        return true;        //超過緩沖最大包,不繼續(xù)播放
    }

    LPWAVEHDR pWaveHeader = new WAVEHDR;

    memset(pWaveHeader, 0, sizeof(WAVEHDR));
    pWaveHeader->dwLoops = 1;
    pWaveHeader->dwBufferLength = len;
    pWaveHeader->lpData = new char[len];
    if (!pWaveHeader->lpData)
    {
        delete pWaveHeader;
        return false;
    }
    memcpy(pWaveHeader->lpData, buffer, len);

    if (::waveOutPrepareHeader(m_hWaveOut, pWaveHeader, sizeof(WAVEHDR)))
    {
        delete pWaveHeader->lpData;
        delete pWaveHeader;
        return false;
    }
    if (::waveOutWrite(m_hWaveOut, pWaveHeader, sizeof(WAVEHDR)))
    {
        delete pWaveHeader->lpData;
        delete pWaveHeader;
        return false;
    }

    m_iBlockNum++;
    return true;
}

三、回調(diào)函數(shù)

void CALLBACK WinAudioPlay::waveOutProc( HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
    WinAudioPlay* pThis=(WinAudioPlay*)dwInstance;

    if(WOM_DONE == uMsg)    //播放完成
    { 
        while(NULL != pThis->m_lpWaveHdrFromCallbackProc)
        {
            boost::this_thread::interruptible_wait(1);
        }
        pThis->m_lpWaveHdrFromCallbackProc = (LPWAVEHDR)dwParam1;
        pThis->m_spbrTgthr->wait();
    }
    return ;
}

四、線程同步播放

void WinAudioPlay::ThrdWaveOutTogether()
{
    while(!m_b_exit)
    {
        m_spbrTgthr->wait();
        if (NULL != m_lpWaveHdrFromCallbackProc)
        {    
            ::waveOutUnprepareHeader(m_hWaveOut, m_lpWaveHdrFromCallbackProc, sizeof(WAVEHDR));
            delete[] m_lpWaveHdrFromCallbackProc->lpData;        
            delete     m_lpWaveHdrFromCallbackProc;
            m_lpWaveHdrFromCallbackProc = NULL;

            (m_iBlockNum > 0)?(m_iBlockNum--):(m_iBlockNum = 0);            
        }
    }
    if (m_hWaveOut != NULL)
    {
        ::waveOutReset(m_hWaveOut);
        ::waveOutClose(m_hWaveOut);
    }
}

五、關(guān)閉線程,釋放資源

WinAudioPlay::~WinAudioPlay()
{    
    m_bPalyStata = false;
    while(0 != m_iBlockNum)
    {
        Sleep(1);
    }
    m_b_exit = true;
    m_spbrTgthr->wait();
    m_sptrdWaveOutTgthr->join();
}

我相信聰明的你,借助msdn能夠很快理解上面意思,我就不多打字了(水平有限,怕誤人子弟~)

但是需要注意以下幾點(diǎn):

一、waveOutProc回調(diào)函數(shù)中絕對不能調(diào)用waveOut系列函數(shù)(可用線程同步實(shí)現(xiàn)通知在另一個(gè)線程調(diào)用)

二、調(diào)用waveOutReset函數(shù)時(shí),函數(shù)執(zhí)行完畢才返回,期間不可以調(diào)用hWaveOut

三、注意釋放資源

and so on...

其實(shí)還有很多,我就不多寫了,以上3點(diǎn)中前兩點(diǎn)處理不好,會發(fā)生線程死鎖。

當(dāng)初我就在上面耗費(fèi)了很長時(shí)間,后來多虧孫總點(diǎn)醒(其實(shí)msdn中有那么一句的。但是E語要加強(qiáng)啊。。。)

最后贈送一個(gè)免費(fèi)的建議,聽不聽由你:不要太過于相信網(wǎng)絡(luò)上的代碼,win32平臺最有說服力的還數(shù)msdn~



歡迎各位轉(zhuǎn)載,但必須在文章頁面中給出作者和原文鏈接!

總結(jié)

以上是生活随笔為你收集整理的waveout系列API实现pcm音频播放的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。