回声就是声音信号经过一系列反射之后,又听到了自己讲话的声音,这就是回声。
在VoIP(Voice over Internet Protocol,基于IP的语音传输 )实时语音通话中,是近端通话者的声音被自己的麦克风拾取后通过网络传到远端,远端扬声器播放出来的声音被麦克风拾取后通过网络又重新发回近端,再加上网络和数据处理等各种延迟的影响,使得近端通话者能够从扬声器中听到自己的刚才所说的话,就产生了回声。
在通信系统中,回声主要分为两类:电路回声和声学回声(线性回声和非线性回声)。
电路回声:通常产生于有线通话中,由于电路回声信号是线性且稳定的,所以比较容易将其消除,用一个简单的线性叠加器就可以实现,不属于本文讨论方向。
电路回声产生原理
直接回声(线性回声):近端扬声器将语音信号播放出来后,被近端麦克风直接采集后得到的回声;直接回声不受环境的印象,与扬声器到麦克风的距离及位置有很大的关系,因此直接回声是一种线性信号。
间接回声(非线性回声):近端扬声器将语音信号播放出来后,语音信号经过复杂多变的墙面反射后由近端麦克风采集;间接回声的大小与房间环境、物品摆放以及墙面吸引系数等等因素有关,因此间接回声是一种非线性信号。
回声消除(Acoustic Echo Cancellation,AEC ):就是在麦克风采集到声音之后,将本地扬声器播放出来的声音从麦克风采集的声音数据中消除掉,使得麦克风录制的声音只有本地用户说话的声音。
回声消除的基本原理:使用自适应滤波算法,以扬声器信号与由它产生的多路径回声的相关性为基础,建立远端信号的语音模型,利用它对回声进行估计,并不断修改滤波器的系数,使得估计值更加逼近真实的回声,然后将回声估计值从麦克风的输入信号中减去,从而达到消除回声的目的。
回声消除的基本步骤:如下图所示
与以上的三个步骤相对应,回声消除也主要由三个大的算法模块组成:
其中「时延估计」决定了AEC的下限,「线性自适应滤波器」决定了 AEC 的上限,「非线性处理」决定了最终的通话体验,特别是回声抑制跟双讲之间的平衡。
注:双讲是指在交互场景中,互动双方或多方同时讲话,其中一方的声音会受到抑制,从而出现断断续续的情况。这是由于回声消除算法“矫枉过正”,消除了部分不该去除的音频信号。
方案 | 硬件回声消除 | Android系统回声消除API | 第三方库回声消除 | ||
---|---|---|---|---|---|
WebRTC | Speex | TRTC/即构/QttAudio | |||
实现方式 | 在硬件电路上集成DSP处理芯片,通过VOICE_COMMUNICATION模式进行录音,自动实现回声消除。 | 利用Android自身带的AcousticEchoCanceler进行回声消除处理 | 接入WebRTC AECM开源库,验证语音通话时回声消除效果 | 接入Speex DSP开源库,验证语音通话时回声消除效果 | 调用其提供的API即可实现 |
是否建议 |
不建议,此方案不通用。当使用摄像头自带的麦克风采集音频,而这些麦克风没有硬件回声消除等处理时,无法实现回声消除。 | 不建议。有些Android设备并未实现回声消除。 | 强力推荐。市面上大多数回声消除方案都是基于此开源库。 | 建议。Speex具有回声消除模块。 | 收费 |
我们知道,通过硬件回声消除和Android系统回声消除API的方式,都有局限性,所以市面上基本上都是采用第三方回声消除方案。
AEC相对较难,要做好很不容易,在WebRTC开源前主要是大公司和专业的算法公司有好的实现方案,一般公司要想产品里有EC就去买算法库,但在WebRTC开源后一些核心的算法(包括AEC/ANS/AGC等)也随之开源,这样众公司开始用WebRTC里的算法,尤其是互联网公司,AEC等算法基本都是基于WebRTC。
开源方案 |
主要功能 |
最后更新时间 |
优点 |
缺点 |
---|---|---|---|---|
webrtc | 网页视频会议 | 2021(已成为W3C正式标准) | 开源,免费,无专利。使用范围广,效果较好,目前几乎所有音视频厂商都基于其开发。 | 项目庞大, 需要自行抽取音频部分进行处理。 |
speex | 音频编解码 | 2016 | 开源,免费,无专利。有基于DSP的算法 | 开发Speex的Xiph.org基金会已经宣布废弃Speex,建议改用Opus取代,但Opus不支持AEC。 |
当使用WebRTC或Speex第三方库进行回声消除的时候,需要将近端采集到的音频数据传入作为源数据,同时需要将远端要播放的音频数据传入作为参考数据,然后还需要传入一个延时间隔(因为播放的声音需要传播,而且麦克风采集声音还有相应的缓冲区),这样第三方库就能工作,从而得到回声消除后的声音。接下来接入这两个三方库看看具体效果。
技术类型 |
WebRTC |
Speex |
回声延时估计模块 |
描述:有回声延时估计方法WebRtc_DelayEstimatorProcessFix。 难点:需要准确估计msInSndCardBuf的值,这也需要相应的延时估计算法。 |
描述:无回声延时估计,初始化时传入filter_length关系到回声消除效果好坏与否。 难点:没有较好的方法去调节回声消除效果。 |
线性自适应滤波算法 |
WebRtcAecm_UpdateChannel方法消除线性回声 |
speex_echo_cancellation方法消除线性回声 |
非线性处理模块 |
WebRtcAecm_CalcSuppressionGain可处理非线性部分回声 |
speex_preprocess_run消除残余回声,和噪声消除放在同一个模块preprocessor.c中处理 |
总体效果对比 |
WebRTC是开源项目中效果最好的,各大厂商基本上都基于此做自家的回声消除 |
有一定效果,但依然存在回声,有时会消减过度,导致声音变小 |
WebRTC:目前效果很差,msInSndCardBuf取40,80,100,140以及400时都未消除回音,且开启回声消除前后的PCM音频波形,对比下来几乎无改变。
Speex:目前效果也不理想,frame_size(或filter_length)取不同值时回音效果都不太好,收敛时间越长回声消除效果越差。
自研回声消除有一定难度,其主要在于对回声延时估计模块的设计。无论是WebRTC还是Speex,对于线性回声消除和非线性回声消除,都做了比较好的处理,但对于回声延时估计,由于应用场景复杂(网络、设备、空间距离、讲话人远近等)的原因,它们都未提供比较好的方案,需要自研。
WebRTC 架构中上下行音频信号处理流程如图,音频 3A(AGC: Automatic gain control; ANS: Adaptive noise suppression; AEC: Acoustic echo cancellation)算法主要集中在上行的发送端对发送信号依次进行回声消除、降噪以及音量均衡(这是 AEC 的处理流程,AECM 的处理流程 ANS 会前置),AGC 会作为压限器作用在接收端对即将播放的音频信号进行限幅。
(1)关键代码:
注:WebRtcAecm_Process方法的最后一个参数msInSndCardBuf,该值需要特别计算才能够取得良好的去回音效果,即:将听筒播放出来的声音被mic采集到时的一个精确的值,才能使AECM达到良好的回音消除效果。
(2)回声消除内部核心:
目前效果很差,msInSndCardBuf取40,80,100,140以及400时都未消除回音,且开启回声消除前后的PCM音频波形,对比下来几乎无改变。
接下来看看有没有更好的算法得到msInSndCardBuf的值。。。
对于传入的msInSndCardBuf值,WebRTC AECM的回声延时估计模块,并未得到准确的延时值。
对于WebRTC AECM内部的多个算法实现,门槛较高,本人暂无能力跟进。
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预处理器。
【1】声学回声消除(Acoustic Echo Cancellation)原理与实现
【2】详解低延时高音质|回声消除与降噪篇
【3】深入浅出 WebRTC AEC(声学回声消除)