一、简介

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数据,采集后的数据会写文件在当前程序的目录下,还有一个停止按钮,停止采集数据。代码比较多,就不贴在下面了,直接在上面下载就可以。

android获得麦克风采样率 麦克风采集的数据格式_android获得麦克风采样率


三、Waveform Audio函数介绍

Waveform Audio能提供的主要功能有:

  1. 打开 / 关闭 / 查询声音设备 ;
  2. 播放波形文件 ;
  3. 设置播放速度 ;
  4. 播放进度控制 ;
  5. 录音 ;
  6. 得到当前的播放位置 ;
  7. 调节音量 .

下面介绍下麦克风音频采集主要用到的函数:

  • 打开录音设备函数
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