回声产生
回声就是声音信号经过一系列反射之后,又听到了自己讲话的声音,这就是回声。
在VoIP(Voice over Internet Protocol,基于IP的语音传输)实时语音通话中,是近端通话者的声音被自己的麦克风拾取后通过网络传到远端,远端扬声器播放出来的声音被麦克风拾取后通过网络又重新发回近端,再加上网络和数据处理等各种延迟的影响,使得近端通话者能够从扬声器中听到自己的刚才所说的话,就产生了回声。
回声分类
在通信系统中,回声主要分为两类:电路回声和声学回声(线性回声和非线性回声)。
电路回声:通常产生于有线通话中,由于电路回声信号是线性且稳定的,所以比较容易将其消除,用一个简单的线性叠加器就可以实现,不属于本文讨论方向。
电路回声产生原理
直接回声(线性回声):近端扬声器将语音信号播放出来后,被近端麦克风直接采集后得到的回声;直接回声不受环境的印象,与扬声器到麦克风的距离及位置有很大的关系,因此直接回声是一种线性信号。
间接回声(非线性回声):近端扬声器将语音信号播放出来后,语音信号经过复杂多变的墙面反射后由近端麦克风采集;间接回声的大小与房间环境、物品摆放以及墙面吸引系数等等因素有关,因此间接回声是一种非线性信号。
回声消除
回声消除(Acoustic Echo Cancellation,AEC):就是在麦克风采集到声音之后,将本地扬声器播放出来的声音从麦克风采集的声音数据中消除掉,使得麦克风录制的声音只有本地用户说话的声音。
回声消除的基本原理:使用自适应滤波算法,以扬声器信号与由它产生的多路径回声的相关性为基础,建立远端信号的语音模型,利用它对回声进行估计,并不断修改滤波器的系数,使得估计值更加逼近真实的回声,然后将回声估计值从麦克风的输入信号中减去,从而达到消除回声的目的。
回声消除的基本步骤:如下图所示
第一步,需要找到参考信号/扬声器信号(蓝色折线)跟麦克风信号(红色折线)之间的延迟,也就是图中的 delay=T。第二步,根据参考信号估计出麦克风信号中的线性回声成分,并将其从麦克风信号中减去,得到残差信号(黑色折线)。第三步,通过非线性的处理将残差信号中的残余回声给彻底抑制掉。
与以上的三个步骤相对应,回声消除也主要由三个大的算法模块组成:
时延估计(Delay Estimation)模块线性自适应滤波器(Linear Adaptive Filter)模块非线性处理(Nonlinear Processing)残余声学回声模块
其中「时延估计」决定了AEC的下限,「线性自适应滤波器」决定了 AEC 的上限,「非线性处理」决定了最终的通话体验,特别是回声抑制跟双讲之间的平衡。
注:双讲是指在交互场景中,互动双方或多方同时讲话,其中一方的声音会受到抑制,从而出现断断续续的情况。这是由于回声消除算法“矫枉过正”,消除了部分不该去除的音频信号。
回声消除方案
Android回声消除方案调研表
我们知道,通过硬件回声消除和Android系统回声消除API的方式,都有局限性,所以市面上基本上都是采用第三方回声消除方案。
AEC相对较难,要做好很不容易,在WebRTC开源前主要是大公司和专业的算法公司有好的实现方案,一般公司要想产品里有EC就去买算法库,但在WebRTC开源后一些核心的算法(包括AEC/ANS/AGC等)也随之开源,这样众公司开始用WebRTC里的算法,尤其是互联网公司,AEC等算法基本都是基于WebRTC。
WebRTC与Speex对比表
当使用WebRTC或Speex第三方库进行回声消除的时候,需要将近端采集到的音频数据传入作为源数据,同时需要将远端要播放的音频数据传入作为参考数据,然后还需要传入一个延时间隔(因为播放的声音需要传播,而且麦克风采集声音还有相应的缓冲区),这样第三方库就能工作,从而得到回声消除后的声音。接下来接入这两个三方库看看具体效果。
技术对比分析
WebTRTC回声消除效果对比分析
WebRTC:目前效果很差,msInSndCardBuf取40,80,100,140以及400时都未消除回音,且开启回声消除前后的PCM音频波形,对比下来几乎无改变。
Speex回声消除效果对比分析
Speex:目前效果也不理想,frame_size(或filter_length)取不同值时回音效果都不太好,收敛时间越长回声消除效果越差。
小结
自研回声消除有一定难度,其主要在于对回声延时估计模块的设计。无论是WebRTC还是Speex,对于线性回声消除和非线性回声消除,都做了比较好的处理,但对于回声延时估计,由于应用场景复杂(网络、设备、空间距离、讲话人远近等)的原因,它们都未提供比较好的方案,需要自研。
WebRTC
WebRTC 架构中上下行音频信号处理流程如图,音频 3A(AGC: Automatic gain control; ANS: Adaptive noise suppression; AEC: Acoustic echo cancellation)算法主要集中在上行的发送端对发送信号依次进行回声消除、降噪以及音量均衡(这是 AEC 的处理流程,AECM 的处理流程 ANS 会前置),AGC 会作为压限器作用在接收端对即将播放的音频信号进行限幅。
(1)关键代码:
WebRtcAecm_Create();WebRtcAecm_Init(aecmInst, sampleRate);//8000 or 16000 Sample rateWebRtcAecm_set_config(aecmInst, config);WebRtcAecm_BufferFarend(aecmInst, far_input, samples) // 填充接收到的远端视频数据。WebRtcAecm_Process(aecmInst, near_input, NULL, out_buffer, samples, 140); // 添加近端采集的数据,内部包含回声,重点为延时时间的获取。
注:WebRtcAecm_Process方法的最后一个参数msInSndCardBuf,该值需要特别计算才能够取得良好的去回音效果,即:将听筒播放出来的声音被mic采集到时的一个精确的值,才能使AECM达到良好的回音消除效果。
(2)回声消除内部核心:
WebRtc_DelayEstimatorProcessFix //回声延时估计WebRtcAecm_UpdateChannel //NLMS:归一化均方最小自适应滤波算法WebRtcAecm_CalcSuppressionGain // NLP:非线性滤波,使用wiener滤波器ComfortNoise // CNG:舒适噪声产生
验证结果
目前效果很差,msInSndCardBuf取40,80,100,140以及400时都未消除回音,且开启回声消除前后的PCM音频波形,对比下来几乎无改变。
后续
接下来看看有没有更好的算法得到msInSndCardBuf的值。。。
对于传入的msInSndCardBuf值,WebRTC AECM的回声延时估计模块,并未得到准确的延时值。
对于WebRTC AECM内部的多个算法实现,门槛较高,本人暂无能力跟进。
Speex
Speex相关API
echo相关API
1、speex_echo_state_init
创建并初始化一个Speex声学回音消除器。
2、speex_echo_ctl
设置一个Speex声学回音消除器的相关参数。
3、speex_echo_cancellation:回声消除函数
speex_echo_cancel已废弃,现改为speex_echo_cancellation,使用Speex声学回音消除器对一个单声道16位有符号整型PCM格式音频数据帧进行声学回音消除。
注:
如果感觉回音消除效果不好,就把rec、play、out这些参数打印日志出来看看,然后调整speex_echo_state_init()函数的filter_length参数,再测试。
当录音里的回音的音量大于播放的音量,则本函数认为这个不是回音,就不会消除掉。这种情况主要在开了麦克风增益、或者喇叭离麦克风特别近时才会产生。
当录音里的回音和播放的声音区别较大时,则本函数认为这个不是回音,就不会消除掉。这种情况主要是麦克风或音响的音质不好造成的。
音频流的刚开始几秒钟内产生的声学回音可能消除不掉,因为声学回音消除算法有收敛时间。
4、speex_echo_capture
使用内部播放缓冲区执行回声消除,延迟两帧,以解释大多数声卡引入的延迟(但它可以关闭!)
5、speex_echo_playback
让回声消除器知道一帧刚刚排队到声卡。
6、speex_echo_state_reet
将一个Speex声学回音消除器重置为初始状态。
7、speex_echo_state_destroy
销毁一个Speex声学回音消除器。
preprocess相关API
1、speex_preprocess_state_init
创建并初始化Speex预处理器。Speex预处理器用于对PCM格式音频数据进行预处理。
2、speex_preprocess_ctl
设置一个Speex预处理器的相关参数。
3、speex_preprocess_run
用一个Speex预处理器对一个单声道16位有符号整型PCM格式音频数据帧进行预处理。
4、speex_preprocess_state_destroy
销毁一个Speex预处理器。
Speex Echo Demo流程图
Speex Echo Demo处理时序图
参考
【1】声学回声消除(Acoustic Echo Cancellation)原理与实现
【2】详解低延时高音质|回声消除与降噪篇
【3】深入浅出 WebRTC AEC(声学回声消除)