一、简介
PCM(脉冲编码调制),它是对连续变化的模拟信号进行抽样、量化和编码产生的,称为PCM(Pulse-code modulation),即脉冲编码调制。这种电的数字信号称为数字基带信号,由PCM电端机产生。数字传输系统都是采用PCM体制。PCM最初并非传输计算机数据用的,而是使交换机之间有一条中继线不是只传送一条电话信号。PCM有两个标准(表现形式)即E1和T1。
G.711是一种由国际电信联盟制定的音频编码方式,又称为ITU-T G.711。G711编码的声音清晰度好,语音自然度高,但压缩效率低,数据量大常在32Kbps以上,常用于电话语音(推荐使用64Kbps)。G.711 标准下主要有两种压缩算法,分别为a-law和u-law。a-law也叫g711a,使用在欧洲和其他地区,这种格式是经过特别设计的,便于数字设备进行快速运算。
最近做了一个语音对讲的需求,在这里记录一下,毕竟好记性不如烂笔头。在电脑端这边对讲分为两方面,一方面是收集设备发过来的声音播放,另一方面采集电脑麦克风的音频数据发送给设备。这里主要是对后者的一些API调用的记录,以实现对电脑麦克风的音频数据的采集,主要分为两种比较常用的格式,PCM和G711a。主要使用的是Windows提供的API函数Waveform Audio API,写了个小demo,代码放在下面了:
二、效果
demo比较简单,就一个设置保存的文件名,可以填比如123.pcm或123.G711a,以及三个按钮,一个采集PCM数据,一个采集G711a数据,采集后的数据会写文件在当前程序的目录下,还有一个停止按钮,停止采集数据。代码比较多,就不贴在下面了,直接在上面下载就可以。
三、Waveform Audio函数介绍
Waveform Audio能提供的主要功能有:
- 打开 / 关闭 / 查询声音设备 ;
- 播放波形文件 ;
- 设置播放速度 ;
- 播放进度控制 ;
- 录音 ;
- 得到当前的播放位置 ;
- 调节音量 .
下面介绍下麦克风音频采集主要用到的函数:
- 打开录音设备函数
MMRESULT waveInOpen(
LPHWAVEIN phwi, // 输入设备句柄
UINT uDeviceID, // 输入设备 ID
LPWAVEFORMATEX pwfx, // 录音格式指针
DWORD dwCallback, // 处理 MM_WIM_*** 消息的回调函数或窗口句柄,线程ID
DWORD dwCallbackInstance,
DWORD fdwOpen // 处理消息方式的符号位
);
- 为录音设备准备缓存函数
MMRESULT waveInPrepareHeader(
HWAVEIN hwi,
PWAVEHDR pwh,
UINT bwh
);
- 给输入设备增加一个缓存
MMRESULT waveInAddBuffer(
HWAVEIN hwi,
LPWAVEHDR pwh,
UINT cbwh
);
- 开始录音
MMRESULT waveInStart( HWAVEIN hwi );
- 清除缓存
MMRESULT waveInUnprepareHeader(
HWAVEIN hwi,
LPWAVEHDR pwh,
UINT cbwh
);
- 停止录音
MMRESULT waveInReset( HWAVEIN hwi );
- 关闭录音设备
MMRESULT waveInClose( HWAVEIN hwi );
- Wave_audio 数据格式
typedef struct {
WORD wFormatTag; // 数据格式,一般为 WAVE_FORMAT_PCM 即脉冲编码
WORD nChannels; // 声道
DWORD nSamplesPerSec; // 采样频率
DWORD nAvgBytesPerSec; // 每秒数据量
WORD nBlockAlign;
WORD wBitsPerSample; // 样本大小
WORD cbSize;
} WAVEFORMATEX;
- waveform-audio 缓存格式
typedef struct {
LPSTR lpData; // 内存指针
DWORD dwBufferLength; // 长度
DWORD dwBytesRecorded; // 已录音的字节长度
DWORD dwUser;
DWORD dwFlags;
DWORD dwLoops; // 循环次数
struct wavehdr_tag * lpNext;
DWORD reserved;
} WAVEHDR;
- 相关消息
MM_WIM_OPEN: 打开设备时消息,在此期间我们可以进行一些初始化工作
MM_WIM_DATA: 当缓存已满或者停止录音时的消息,处理这个消息可以对缓存进行重新分配,实现不限长度录音
MM_WIM_CLOSE:关闭录音设备时的消息。
四、PCM转G711a
Windows提供的这套API虽然可以很好的实现采集麦克风中的数据,但是我发现好像只能采集到PCM格式的数据,试了很多方法也不能直接采集到G711a格式的数据。所以这里我参考了别的大神的博客,直接把PCM格式的数据转成G711a,参考的博客地址我放在下面了,里面详细的讲解了G711a的编码方式,感兴趣的可以去学习一下。我这里就直接使用了大神的代码把PCM转成G711a。
如果想要看自己采集到的数据有没有问题,可以使用ffplay播放一下,ffplay是一个使用了FFmpeg和sdl库的一个媒体播放工具。
把采集到的G711a和PCM格式的文件放在ffmplay同一目录下,然后在cmd命令行里进入ffmplay所在的路径,输入下面的命令就可以播放了:
播放g711a:
ffplay.exe -f alaw -ar 16000 -ac 1 test.g711a
播放pcm:
ffplay.exe -f s16le -ar 16000 -ac 1 test.pcm