<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    Windows 下音頻數據采集和播放

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    音頻操作所需頭文件和鏈接庫

                  

    #include<mmsystem.h>
    #include<mmreg.h>
    #pragma  comment(lib"winmm.lib")

     

     

            由于音頻采集過程是一個持續過程,所以建議為它們各自分配一個線程,而使用MFC的 CWinThread 類是一個不錯的選擇,筆者就是利用CWinThread類將這兩個功能封裝成了兩個獨立的類,為以后的使用提供了很大的便利性。筆者在此為讀者提供本人寫好的一個工程,此工程為視頻語音采集的不完善版,目前實現語音本地采集與播放,VFW視頻采集與顯示(視頻不清晰),在后續章節會將VFW視頻采集進行總結,敬請期待。。。。。

    工程下載地址:http://pan.baidu.com/share/link?shareid=190628&uk=2735225556 中選擇  VideoPlay.rar 下載,此項目是用vs2010編譯

    一、音頻采集

    操作步驟:

    1、分配數據buffer,通過WAVEHDR結構體保存,準備存儲采集到的音頻數據,此處應該根據采集頻率設置足量的buffer

    void CRecodeSound::PreCreateHeader()
    {
        for(int i=0;i<MAXRECBUFFER;i++)
            m_RecHead[i]=CreateWaveHeader();
        m_IsAllocated = 1;
    }
    LPWAVEHDR  CRecodeSound::CreateWaveHeader()
    {
        LPWAVEHDR lpHdr = new WAVEHDR;

     

        if(lpHdr==NULL)
        {
            m_RecodeLog.WriteString(TEXT("\n Unable to allocate the memory"));
            return NULL;
        }

        ZeroMemory(lpHdr, sizeof(WAVEHDR));
        char* lpByte = new char[RECBUFFER];//m_WaveFormatEx.nBlockAlign*SOUNDSAMPLES)];

        if(lpByte==NULL)
        {
            m_RecodeLog.WriteString(TEXT("\n Unable to allocate the memory"));
            return NULL;
        }
        lpHdr->lpData =  lpByte;
        lpHdr->dwBufferLength =RECBUFFER;   // (m_WaveFormatEx.nBlockAlign*SOUNDSAMPLES);
        return lpHdr;

    }

     

     

    2、初始化音頻格式結構體 WAVEFORMATEX。

    memset(&m_WaveFormatEx, 0, sizeof(m_WaveFormatEx));
    m_WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;//聲音格式為PCM        
    m_WaveFormatEx.nChannels = 1;    //采樣聲道數,對于單聲道音頻設置為1,立體聲設置為2
    m_WaveFormatEx.wBitsPerSample = 8;//采樣比特  8bits/次
    m_WaveFormatEx.cbSize = 0;//一般為0
    m_WaveFormatEx.nSamplesPerSec = 8000; //采樣率 16000 次/秒
    m_WaveFormatEx.nBlockAlign = 1; //一個塊的大小,采樣bit的字節數乘以聲道數
    m_WaveFormatEx.nAvgBytesPerSec = 8000; //每秒的數據率,就是每秒能采集多少字節的數據

     

     

    3、waveInOpen打開音頻輸入設備準備開始采集

    //開啟音頻采集
    MMRESULT mmReturn = ::waveInOpen( &m_hRecord, WAVE_MAPPER,
        &m_WaveFormatEx, ::GetCurrentThreadId(), 0, CALLBACK_THREAD);

     

    //Error has occured while opening device

    if(mmReturn != MMSYSERR_NOERROR ) //打開采集失敗
    {
        displayError(mmReturn,"Open");
        return ;//FALSE;
    }

     

     

    4、waveInPrepareHeader 和 waveInAddBuffer 配合將準備好的buffer提供給設備

    //將準備好的buffer提供給音頻輸入設備
    for(int i=0; i < MAXRECBUFFER ; i++)
    {
        //準備一個bufrer給輸入設備
        mmReturn = ::waveInPrepareHeader(m_hRecord,m_RecHead[i], sizeof(WAVEHDR));
        //發送一個buffer給指定的輸入設備,當buffer填滿將會通知程序
        mmReturn = ::waveInAddBuffer(m_hRecord, m_RecHead[i], sizeof(WAVEHDR));
    }

     

     

    5、waveInStart正式開始采集

    //開啟指定的輸入采集設備
    mmReturn = ::waveInStart(m_hRecord);

     

    if(mmReturn!=MMSYSERR_NOERROR )  //開始采集失敗
        displayError(mmReturn,"Start");
    else
        m_IsRecoding = TRUE;

     

     

    6、每當一個buffer數據填滿時,會觸發 MM_WIM_DATA 消息,在程序中捕獲此消息,通過消息傳遞過來的 lParam,為指向數據buffer的WAVEHDR指針。采集到此數據時可以根據程序需要對其做相應的處理。本程序是直接將采集到的數據提供給播放線程直接播放,你也可以通過socket發送到遠端在播放,就可以網絡語音了。

    void CRecodeSound::OnSoundData(WPARAM wParam, LPARAM lParam)
    {
        m_RecodeLog.WriteString(TEXT("\nIn the onsound data"));

     

        if(m_IsRecoding==FALSE) //如果當前不在采集狀態
            return ;//FALSE;

        LPWAVEHDR lpHdr = (LPWAVEHDR) lParam;

        if(lpHdr->dwBytesRecorded==0 || lpHdr==NULL)
            return ;//ERROR_SUCCESS;

        //使采集過程,知道此buffer已經沾滿,不能再填充
        ::waveInUnprepareHeader(m_hRecord, lpHdr, sizeof(WAVEHDR));

        //將采集到的聲音發送給播放線程
        ((CVideoPlayDlg *)m_pDlg)->m_pPlaySound->PostThreadMessage(WM_PLAYSOUND_PLAYBLOCK, lpHdr->dwBytesRecorded, (LPARAM)lpHdr->lpData);
        
        // Send recorded audio to remote host…
        /*
        if(lpHdr->lpData!=NULL )
            ( (CVideoNetDlg*) dlg )->daudio.SendAudioData((unsigned char *)lpHdr->lpData,lpHdr->dwBytesRecorded);
        */

        if(m_IsRecoding)
        {
            //重新將buffer恢復到準備填充狀態
            ::waveInPrepareHeader(m_hRecord, lpHdr, sizeof(WAVEHDR));
            ::waveInAddBuffer(m_hRecord, lpHdr, sizeof(WAVEHDR));
        }
    }

     

     

    7、在要停止采集是使用waveInStop停止采集數據。

    mmReturn = ::waveInStop(m_hRecord);

     

     

    8、停止采集成功,立即waveInReset重置設備,重置設備將會導致所有的采集buffer反饋給程序。

    if(!mmReturn) //停止采集成功,立即重置設備,重置設備將會導致所有的buffer反饋給程序
    {
        m_IsRecoding = FALSE;
        mmReturn = ::waveInReset(m_hRecord);  //重置設備
    }

     

     

    9、延時一段時間,等待所有的數據buffer都被程序處理完成

    Sleep(500); //等待一段時間,使buffer反饋完成

     

     

    10、waveInClose關閉設備

    if(!mmReturn) //重置設備成功,立即關閉設備
            mmReturn = ::waveInClose(m_hRecord); //關閉設備

     

     

    二、音頻播放

    操作步驟:

    1、初始化音頻數據格式結構體 WAVEFORMATEX

    //初始化音頻格式結構體
    memset(&m_WaveFormatEx, 0, sizeof(m_WaveFormatEx));
    m_WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
    m_WaveFormatEx.nChannels = 1;
    m_WaveFormatEx.wBitsPerSample = 8;
    m_WaveFormatEx.cbSize = 0;
    m_WaveFormatEx.nSamplesPerSec = 8000;
    m_WaveFormatEx.nAvgBytesPerSec = 8000 ;
    m_WaveFormatEx.nBlockAlign = 1;

     

     

    2、打開音頻輸出設備

    //打開音頻輸出設備
        mmReturn = ::waveOutOpen( &m_hPlay, WAVE_MAPPER,
            &m_WaveFormatEx, ::GetCurrentThreadId(), 0, CALLBACK_THREAD);

     

     

    3、設置音頻輸出音量

    if(mmReturn) //打開設備失敗
        displayError(mmReturn,"PlayStart");    
    else
    {    
        m_IsPlaying = TRUE;
        DWORD volume = 0xffffffff;
        waveOutSetVolume(m_hPlay, volume);//設置輸出設備的輸出量
    }

     

     

    4、等待要輸出的數據,通過waveOutPrepareHeader將數據提交給設備準備輸出,通過waveOutWrite將提交給設備的數據輸出。

    void CPlaySound::OnWriteSoundData(WPARAM wParam, LPARAM lParam)
    {
        MMRESULT mmResult = 0;
        int length=(int) wParam;
        
        if(m_IsPlaying == FALSE)
            return ; //FALSE;

     

        m_PlayLog.WriteString(TEXT("\nplaying sound data…."));

        // Prepare wave header for playing 
        WAVEHDR *lpHdr=new WAVEHDR;
        memset(lpHdr,0,sizeof(WAVEHDR));
        lpHdr->lpData=(char *)lParam;
        lpHdr->dwBufferLength=length;

        //將要輸出的數據寫入buffer
        mmResult = ::waveOutPrepareHeader(m_hPlay, lpHdr, sizeof(WAVEHDR));

        if(mmResult)
        {
            m_PlayLog.WriteString(TEXT("\nError while preparing header"));
            return ;//ERROR_SUCCESS;
        }

        //將輸出數據發送給輸出設備
        mmResult = ::waveOutWrite(m_hPlay, lpHdr, sizeof(WAVEHDR));

        if(mmResult)
        {
            m_PlayLog.WriteString(TEXT("\nError while writing to device"));
            return ;//ERROR_SUCCESS;                
        }
        return ;//ERROR_SUCCESS;
    }

     

     

    5、當提交給設備的數據輸出結束,設備會發送一條MM_WOM_DONE消息反饋給設備,設備應該用waveOutUnprepareHeader將提交給設備輸出的數據清除。

    void CPlaySound::OnEndPlaySoundData(WPARAM wParam, LPARAM lParam)
    {
        LPWAVEHDR lpHdr = (LPWAVEHDR) lParam;

     

        if(lpHdr)
        {
            ::waveOutUnprepareHeader(m_hPlay, lpHdr, sizeof(WAVEHDR));//音頻輸出結束,清空buffer
        }
        return ;//ERROR_SUCCESS;
    }

     

     

    6、結束輸出前先用waveOutReset重置輸出設備,重置能夠使輸出設備全部buffer輸出結束,所以在waveOutReset后要延遲一段時間,然后調用waveOutClose關閉設備。

    void CPlaySound::OnStopPlaying(WPARAM wParam, LPARAM lParam)
    {

     

        MMRESULT mmReturn = 0;

        if(m_IsPlaying == FALSE)
            return;// FALSE;

        m_PlayLog.WriteString(TEXT("\n Stopped  playing"));

        mmReturn = ::waveOutReset(m_hPlay);//重置輸出設備,重置能夠使輸出設備全部buffer輸出結束

        if(!mmReturn)
        {
            m_IsPlaying = FALSE;
            Sleep(500); //等待所有buffer輸出完成
            mmReturn = ::waveOutClose(m_hPlay);//關閉設備
        }
    }

     

     from:http://xzben.com/windows-%E4%B8%8B%E9%9F%B3%E9%A2%91%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86%E5%92%8C%E6%92%AD%E6%94%BE/

     RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全