Windows 下音频数据采集和播放
2020-11-18 01:48
标签:des com http class div c code log t size sp
由于音频采集过程是一个持续过程,所以建议为它们各自分配一个线程,而使用MFC的 CWinThread
类是一个不错的选择,笔者就是利用CWinThread类将这两个功能封装成了两个独立的类,为以后的使用提供了很大的便利性。笔者在此为读者提供本人写好的一个工程,此工程为视频语音采集的不完善版,目前实现语音本地采集与播放,VFW视频采集与显示(视频不清晰),在后续章节会将VFW视频采集进行总结,敬请期待。。。。。 工程下载地址:http://pan.baidu.com/share/link?shareid=190628&uk=2735225556 中选择
VideoPlay.rar 下载,此项目是用vs2010编译 1、分配数据buffer,通过WAVEHDR结构体保存,准备存储采集到的音频数据,此处应该根据采集频率设置足量的buffer if(lpHdr==NULL) ZeroMemory(lpHdr, sizeof(WAVEHDR)); if(lpByte==NULL) } 2、初始化音频格式结构体 WAVEFORMATEX。 3、waveInOpen打开音频输入设备准备开始采集 //Error has occured while opening device if(mmReturn != MMSYSERR_NOERROR
) //打开采集失败 4、waveInPrepareHeader 和 waveInAddBuffer 配合将准备好的buffer提供给设备 5、waveInStart正式开始采集 if(mmReturn!=MMSYSERR_NOERROR
) //开始采集失败 6、每当一个buffer数据填满时,会触发 MM_WIM_DATA 消息,在程序中捕获此消息,通过消息传递过来的
lParam,为指向数据buffer的WAVEHDR指针。采集到此数据时可以根据程序需要对其做相应的处理。本程序是直接将采集到的数据提供给播放线程直接播放,你也可以通过socket发送到远端在播放,就可以网络语音了。 if(m_IsRecoding==FALSE) //如果当前不在采集状态 LPWAVEHDR lpHdr = (LPWAVEHDR) lParam; if(lpHdr->dwBytesRecorded==0 ||
lpHdr==NULL) //使采集过程,知道此buffer已经沾满,不能再填充 //将采集到的声音发送给播放线程 if(m_IsRecoding) 7、在要停止采集是使用waveInStop停止采集数据。 8、停止采集成功,立即waveInReset重置设备,重置设备将会导致所有的采集buffer反馈给程序。 9、延时一段时间,等待所有的数据buffer都被程序处理完成 10、waveInClose关闭设备 1、初始化音频数据格式结构体 WAVEFORMATEX 2、打开音频输出设备 3、设置音频输出音量 4、等待要输出的数据,通过waveOutPrepareHeader将数据提交给设备准备输出,通过waveOutWrite将提交给设备的数据输出。 m_PlayLog.WriteString(TEXT("\nplaying sound
data….")); // Prepare wave header for
playing //将要输出的数据写入buffer if(mmResult) //将输出数据发送给输出设备 if(mmResult) 5、当提交给设备的数据输出结束,设备会发送一条MM_WOM_DONE消息反馈给设备,设备应该用waveOutUnprepareHeader将提交给设备输出的数据清除。 if(lpHdr) 6、结束输出前先用waveOutReset重置输出设备,重置能够使输出设备全部buffer输出结束,所以在waveOutReset后要延迟一段时间,然后调用waveOutClose关闭设备。 MMRESULT mmReturn = 0; if(m_IsPlaying ==
FALSE) m_PlayLog.WriteString(TEXT("\n
Stopped playing")); mmReturn =
::waveOutReset(m_hPlay);//重置输出设备,重置能够使输出设备全部buffer输出结束 if(!mmReturn) 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 下音频数据采集和播放,搜素材,soscw.com Windows 下音频数据采集和播放 标签:des com http class div c code log t size sp 原文地址:http://www.cnblogs.com/lidabo/p/3701959.html音频操作所需头文件和链接库
#include
#pragma comment(lib, "winmm.lib")
一、音频采集
操作步骤:
{
for(int i=0;i
m_IsAllocated
=
1;
}
LPWAVEHDR CRecodeSound::CreateWaveHeader()
{
LPWAVEHDR
lpHdr = new WAVEHDR;
{
m_RecodeLog.WriteString(TEXT("\n
Unable to allocate the
memory"));
return NULL;
}
char*
lpByte
= new char[RECBUFFER];//m_WaveFormatEx.nBlockAlign*SOUNDSAMPLES)];
{
m_RecodeLog.WriteString(TEXT("\n
Unable to allocate the
memory"));
return NULL;
}
lpHdr->lpData
= lpByte;
lpHdr->dwBufferLength
=RECBUFFER; //
(m_WaveFormatEx.nBlockAlign*SOUNDSAMPLES);
return lpHdr;
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; //每秒的数据率,就是每秒能采集多少字节的数据
MMRESULT mmReturn = ::waveInOpen(
&m_hRecord, WAVE_MAPPER,
&m_WaveFormatEx,
::GetCurrentThreadId(), 0, CALLBACK_THREAD);
{
displayError(mmReturn,"Open");
return ;//FALSE;
}
for(int i=0;
i {
//准备一个bufrer给输入设备
mmReturn
=
::waveInPrepareHeader(m_hRecord,m_RecHead[i], sizeof(WAVEHDR));
//发送一个buffer给指定的输入设备,当buffer填满将会通知程序
mmReturn
= ::waveInAddBuffer(m_hRecord,
m_RecHead[i], sizeof(WAVEHDR));
}
mmReturn = ::waveInStart(m_hRecord);
displayError(mmReturn,"Start");
else
m_IsRecoding
= TRUE;
{
m_RecodeLog.WriteString(TEXT("\nIn
the onsound data"));
return ;//FALSE;
return ;//ERROR_SUCCESS;
::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);
*/
{
//重新将buffer恢复到准备填充状态
::waveInPrepareHeader(m_hRecord,
lpHdr, sizeof(WAVEHDR));
::waveInAddBuffer(m_hRecord,
lpHdr, sizeof(WAVEHDR));
}
}
{
m_IsRecoding
= FALSE;
mmReturn =
::waveInReset(m_hRecord); //重置设备
}
mmReturn
= ::waveInClose(m_hRecord); //关闭设备
二、音频播放
操作步骤:
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;
mmReturn =
::waveOutOpen( &m_hPlay,
WAVE_MAPPER,
&m_WaveFormatEx,
::GetCurrentThreadId(), 0, CALLBACK_THREAD);
displayError(mmReturn,"PlayStart");
else
{
m_IsPlaying
= TRUE;
DWORD volume =
0xffffffff;
waveOutSetVolume(m_hPlay,
volume);//设置输出设备的输出量
}
{
MMRESULT mmResult =
0;
int length=(int)
wParam;
if(m_IsPlaying
==
FALSE)
return ; //FALSE;
WAVEHDR
*lpHdr=new WAVEHDR;
memset(lpHdr,0,sizeof(WAVEHDR));
lpHdr->lpData=(char *)lParam;
lpHdr->dwBufferLength=length;
mmResult
= ::waveOutPrepareHeader(m_hPlay,
lpHdr, sizeof(WAVEHDR));
{
m_PlayLog.WriteString(TEXT("\nError
while preparing
header"));
return ;//ERROR_SUCCESS;
}
mmResult
= ::waveOutWrite(m_hPlay, lpHdr, sizeof(WAVEHDR));
{
m_PlayLog.WriteString(TEXT("\nError
while writing to
device"));
return ;//ERROR_SUCCESS;
}
return ;//ERROR_SUCCESS;
}
{
LPWAVEHDR lpHdr = (LPWAVEHDR)
lParam;
{
::waveOutUnprepareHeader(m_hPlay,
lpHdr, sizeof(WAVEHDR));//音频输出结束,清空buffer
}
return ;//ERROR_SUCCESS;
}
{
return;//
FALSE;
{
m_IsPlaying
=
FALSE;
Sleep(500); //等待所有buffer输出完成
mmReturn
=
::waveOutClose(m_hPlay);//关闭设备
}
}