APM音频降噪模块使用及效果分析

目前比较好的开源音频降噪方法,一是speex,另外一个就是webrtc中的NoiseSuppression模块。speex是一个强大点音频处理工具,除了包含speex编解码外还有对于音频效果处理回声消除、自动增益与噪声抑制。WebRTC的强大自不必提,自从Google开源gips的音频处理技术后,很多做实时通讯的公司都在使用WebRTC的VoiceEngine做音频处理。VoiceEngine本是对于实时音视频通讯而设计的,但也可以摘取其中near end的一些处理应用到直播的推流端来优化音频效果,增加音频的体验,比如降噪,解决环境音较重问题;比如自动增益,解决主播离手机或其他直播设备较远(还处于近场)时采集到声音较小的问题。

APM(Audio Preprocessing Module)为VoiceEngine层级的音频处理模块,本文介绍了在直播推流中如何使用APM进行音频降噪,并对降噪效果进行了简单分析

一. 介绍

进入正题前先简单了解下WebRTC的结构,WebRTC由语音引擎,视频引擎和网络传输三大模块组成,其中语音引擎是WebRTC中最具价值的技术之一。

WebRTC总体架构图

语音引擎的一般工作流程如下:

  1. 发起端进行音频采集;
  2. 采集到的音频数据进行回声消除,噪音抑制,自动增益控制处理;
  3. 音频编码;
  4. 通过网路传输到接收端;
  5. 到达接收端,先进入NetEQ模块进行抖动消除,丢包隐藏解码等操作;
  6. 将处理过后的音频数据送入声卡设备进行播放。
语音引擎的工作流程

降噪NS模块(NoiseSuppression),是VoiceEngine中一个关键的语音信号处理组件。在 VOIP 语音通信过程中,来自周围环境和传输媒介引入的噪声、通信设备内部电噪声乃至其它讲话者的干扰不可避免地会对正常语音通信产生影响。这些干扰使接收端接收到的语音成为受噪声污染的带噪语音信号。从带噪语音信号中最大限度提取纯净的原始语音是噪声抑制的主要目标。

二. APM集成说明

2.1 提取编译APM

WebRTC源码链接https://chromium.googlesource.com/external/webrtc/

APM模块的提取与编译可以参考这篇文章,不过版本略旧,模块与新版本略有区别。大家可以同步最新版本进行测试,以下为使用较新版本提取出的apm文件结构

APM文件结构

提取编译完成后,我们看一下APM的主要接口文件/webrtc/modules/audio_processing/include/audio_processing.h,APM提供了简单易用的接口,将AEC、AGC、VAD、NS等模块都包含在一个处理接口中,audio_processing.h中包含所有需要的接口,调用一个process接口即可实现所有音频处理功能,但同样因为如此,想将某一块功能剥离出来也比较麻烦。audio_processing.h注释写的也很详细,不过在代码更新的时候注释没有相应的更新,有些接口已经废弃,网上大多数的对调用流程的说明还是停留在旧版本的注释上。下面通过噪音抑制模块的使用,来说明APM对音频的处理流程以及可能会遇到的一些坑。

2.2 APM关键数据结构说明

2.2.1 整型格式pcm与浮点格式pcm

APM中的接口根据输入数据格式不同分为两类,int16 interfacesfloat interfaces

  • 整型格式PCM,现在终端用户用的最多的,是16位的整数,音乐制作方用的最多的,是24位的整数。人听力的动态范围大约有85dB,16位整数有65536个不同的取值,动态区间是96dB。 如果能够完全利用起来,其实已经足以满足人类对动态范围的需求。但整数格式的数字信号处理,不可避免的会产生误差,在只利用8,9位整数的情况下,产生1位的误差就会产生-50dB左右的噪音,如果误差更大,噪音就更明显。
  • 使用浮点格式来保存音频数据,对于正确还原声音动态以及减小音效处理时产生的误差是十分有利的。但浮点运算的复杂度,要远远大于整数运算的复杂度,而且浮点格式在播放的时候还是需要把浮点数转化为整数,才能进行数模转换,而得到扬声器能够播放的模拟信号。

考虑到终端采集到的pcm为整型格式,如果使用浮点格式处理,还需要经过两次转换,而且浮点处理会增加cpu消耗(这点没有测试...),所以最后使用了int16的接口进行降噪。

2.2.2 AudioFrame类

在VoiceEngine擎中,进行音频数据操作的基本单位为 AudioFrame。主要成员变量如下:

int  id_;
// RTP timestamp of the first sample in the AudioFrame.
uint32_ttimestamp_;
// Time since the first frame in milliseconds.
// -1 represents an uninitialized value.
int64_telapsed_time_ms_;
// NTP time of the estimated capture time in local timebase in milliseconds.
// -1 represents an uninitialized value.
int64_tntp_time_ms_;
int16_tdata_[kMaxDataSizeSamples];
size_tsamples_per_channel_;
intsample_rate_hz_;
size_tnum_channels_;
SpeechTypespeech_type_;
VADActivityvad_activity_;
boolinterleaved_;

其中:

  • id_ :记录的是这个 AudioFrame 对应的 channelId,即属于哪个与会者终端。
  • timestamp_ :用于编解码。
  • data_ :存放待处理的音频帧
  • samples_per_channel_ :每个声道包含的采样数
  • sample_rate_hz_ :采样频率。每一种编解码方式都有对应的采样频率。另外目前降噪支持8K、16K、32K、48K
  • num_channels_ :音频采样声道数。
  • speech_type_ :音频数据类型。此处是一个枚举变量,类型有 kNormalSpeech,kPLC,kCNG,kPLCCNG,kUndefined。
  • vad_activity_:同样是一个枚举变量,表示的是经过静音检测后该 AudioFrame 对应的类型。

2.3 调用流程

APM操作两个一帧接一帧的音频流。一个主流,一个逆向流。所有的处理都将被应用到主流的帧,这些帧通过ProcessStream函数传递过去。逆向流的帧被一些组件拿去分析,逆向流的帧通过AnalyzeReverseStream函数传递过去。这里作为推流端没有逆向流,只有主流,将采集到的音频数据输入就可以了。

组件接口遵循类似的模式设计,通过APM中相应的getter函数访问。 所有的组件在创建时默认都是不可用的。启用一个组件,新的设置将会被应用到APM。启用组件会触发内存分配和初始化,以允许这个组件开始处理音频流。 基于下面的假设,提供了线程安全,用以减少锁的开销:

  • 在ProcessStream的时候,流的getter和setters方法应该在同一个线程被调用。更确切的说,流的方法绝对不能在ProcessStream的同时被调用。
  • 参数的getter和setter绝不能同时调用。

2.3.1 使用示例

APM描述降噪相关接口如下:

1. 创建APM实例,AudioProcessing::Create()
为需要处理的每个主流使用一个实例。 在客户端,这通常是near-end流的一个实例,以及需要处理的每个远端流的附加实例。 在服务器端,这通常是每个传入流的一个实例。也可以调用带参构造函数,传递一些配置项。

2. 创建AudioFrame实例
设置 sample_rate_hz_、num_channels_、samples_per_channel_

3. 启用噪音抑制组件,设置降噪等级
apm->noise_suppression()->set_level(kVeryHigh);
apm->noise_suppression()->Enable(true);

4. 处理音频数据
apm->ProcessStream(capture_frame);

5. 结束app,删除amp
// Close the application... delete apm;

2.4 多采样率适配

// APM accepts only linear PCM audio data in chunks of 10 ms. The int16
// interfaces use interleaved data, while the float interfaces use deinterleaved data.

// The int16 interfaces require: only |NativeRate|s be used.
// The float interfaces accept arbitrary rates.

APM仅能接受以10ms长度的线性pcm音频数据,对于16bit pcm,降噪只能支持NativeRate中测采样率,即8k、16k、32、48k,回声消除、自动增益也同样如此。对于32位或64位浮点数pcm可以支持输入任意采样率且去交错的多声道pcm。

enum NativeRate {
  kSampleRate8kHz = 8000,
  kSampleRate16kHz = 16000,
  kSampleRate32kHz = 32000,
  kSampleRate48kHz = 48000
};

从int16的接口ProcessStream的实现看,也对于其他的采样率也是不支持的

// Must be a native rate.
if (frame->sample_rate_hz_ != kSampleRate8kHz &&
    frame->sample_rate_hz_ != kSampleRate16kHz &&
    frame->sample_rate_hz_ != kSampleRate32kHz &&
    frame->sample_rate_hz_ != kSampleRate48kHz) {
  return kBadSampleRateError;
}

如果在这两处加上其他的采样率,处理结果也是有问题的,噪音降低但是会引入其它杂音。所以在需要处理其它采样率时有两种选择,一种是先进行重采样,转为支持的采样格式后再进行降噪;另一种是转换为浮点数格式,进行降噪处理,处理完成后再转换为16bit格式,因为目前浮点数格式只能转换成整数,才能进行数模转换,而得到扬声器能够播放的模拟信号。浮点数pcm能减小处理过程中的精度损失,但运算的复杂度,要远远大于整数运算的复杂度,处理过程cpu的消耗也会更大。

三. 降噪效果分析

APM集成好了,现在来测试下效果。我们使用audition进行分析。

3.1 直观感受

输入16000HZ 16bit mono 音频数据观察降噪效果:

降噪前音频
降噪后音频

上图为降噪前,下图为降噪后,可以看出降噪前后对比比较明显,降噪后整体整体能量有所下降,音频较低处下降更为明显;实际感受降噪后环境噪音大幅度降低,但人声也会略有降低。

3.2 不同level降噪效果

采集48000HZ 16bit stereo音频数据,降噪有4个level(kLow、kModerate、kHigh、kVeryHigh)为方便对比,将采集到的音频数据存储到本地文件,从文件中读取数据依次使用没有level进行处理。

降噪前音频
Low Level降噪后音频
Moderate Level降噪后音频
High Level降噪后音频
VeryHigh Level降噪后音频

继续对比其他level的处理结果,发现随着level的提高,频域上较低的声音逐渐被消掉,噪音消的越来越干净,但level越高声音的细节也损失也越大,整体音量也有减小的趋势,实际用歌曲来测试发现立体声效果随level提高也越来越弱。

四. 总结

WebRTC的降噪效果不错,但降噪的同时对人声也会略有影响,所以还是要根据需要选择适合的降噪等级。

转载请注明:
作者金山视频云,首发简书 Jianshu.com


也欢迎大家使用我们的直播/短视频SDK,SDK已经支持APM的降噪功能。

有关音视频的更多精彩内容,请参考https://github.com/ksvc
视频云技术交流群(QQ):574179720。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 作者:郑童宇GitHub:https://github.com/CrazyZty 1.前言 音频合成在现实生活中应...
    郑童宇阅读 9,971评论 17 57
  • 摘要 该配置文件定义了支持高质量音频分发所需的Bluetooth®设备的要求。这些要求以终端用户服务的方式表达,并...
    公子小水阅读 9,538评论 0 4
  • 遇见你,以为你会是对的人,但是相处越久就越发现我们真的不适合。思想高度不在同一个层面,喜好不同,越来越没有话题聊,...
    七分醉三分醒阅读 184评论 0 0
  • 又到周末啦,想着还有不到二十小时又要开始上班了,心里有木有很期待。一起来学英语压压惊吧,英语不能停,一起high起...
    小多媛媛阅读 278评论 0 0