天天看點

Windows 下音頻資料采集和播放音頻操作所需頭檔案和連結庫一、音頻采集二、音頻播放

#include<mmsystem.h>

#include<mmreg.h>

#pragma  comment(lib, "winmm.lib")

由于音頻采集過程是一個持續過程,是以建議為它們各自配置設定一個線程,而使用mfc的 cwinthread 類是一個不錯的選擇,筆者就是利用cwinthread類将這兩個功能封裝成了兩個獨立的類,為以後的使用提供了很大的便利性。筆者在此為讀者提供本人寫好的一個工程,此工程為視訊語音采集的不完善版,目前實作語音本地采集與播放,vfw視訊采集與顯示(視訊不清晰),在後續章節會将vfw視訊采集進行總結,敬請期待。。。。。 工程下載下傳位址: 中選擇  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)     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填滿将會通知程式 = ::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,         ::waveinaddbuffer(m_hrecord, 7、在要停止采集是使用waveinstop停止采集資料。 mmreturn = ::waveinstop(m_hrecord); 8、停止采內建功,立即waveinreset重置裝置,重置裝置将會導緻所有的采集buffer回報給程式。 if(!mmreturn) //停止采內建功,立即重置裝置,重置裝置将會導緻所有的buffer回報給程式 = false;     mmreturn = ::waveinreset(m_hrecord);  //重置裝置 9、延時一段時間,等待所有的資料buffer都被程式處理完成 sleep(500); //等待一段時間,使buffer回報完成 10、waveinclose關閉裝置 if(!mmreturn) //重置裝置成功,立即關閉裝置         mmreturn = ::waveinclose(m_hrecord); //關閉裝置
1、初始化音頻資料格式結構體 waveformatex //初始化音頻格式結構體 wave_format_pcm; m_waveformatex.nchannels = m_waveformatex.wbitspersample = 8; 0; m_waveformatex.nsamplespersec = 8000; = 8000 ; m_waveformatex.nblockalign = 1; 2、打開音頻輸出裝置 //打開音頻輸出裝置 ::waveoutopen( &m_hplay, wave_mapper,         &m_waveformatex, 3、設定音頻輸出音量 if(mmreturn) //打開裝置失敗     displayerror(mmreturn,"playstart");     {         m_isplaying     dword volume = 0xffffffff;     waveoutsetvolume(m_hplay, volume);//設定輸出裝置的輸出量
4、等待要輸出的資料,通過waveoutprepareheader将資料送出給裝置準備輸出,通過waveoutwrite将送出給裝置的資料輸出。 void cplaysound::onwritesounddata(wparam wparam, lparam     mmresult mmresult =     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,     if(mmresult)         m_playlog.writestring(text("\nerror while preparing header"));     //将輸出資料發送給輸出裝置 = ::waveoutwrite(m_hplay, lphdr, sizeof(wavehdr)); 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 6、結束輸出前先用waveoutreset重置輸出裝置,重置能夠使輸出裝置全部buffer輸出結束,是以在waveoutreset後要延遲一段時間,然後調用waveoutclose關閉裝置。 void cplaysound::onstopplaying(wparam wparam, lparam     mmresult mmreturn = 0;     if(m_isplaying ==         return;// false;     m_playlog.writestring(text("\n stopped  playing")); ::waveoutreset(m_hplay);//重置輸出裝置,重置能夠使輸出裝置全部buffer輸出結束     if(!mmreturn)         m_isplaying         sleep(500); //等待所有buffer輸出完成 ::waveoutclose(m_hplay);//關閉裝置  from: