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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

Windows 下音频数据采集和播放

發布時間:2025/3/15 windows 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Windows 下音频数据采集和播放 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

??????????????

#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/

總結

以上是生活随笔為你收集整理的Windows 下音频数据采集和播放的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。