乐趣区

关于webrtc:深入浅出-WebRTC-AEC声学回声消除

前言:近年来,音视频会议产品晋升着工作协同的效率,在线教育产品冲破着传统教育模式的种种限度,娱乐互动直播产品丰盛着生存社交的多样性,背地都离不开音视频通信技术的优化与翻新,其中音频信息内容传递的流畅性、完整性、可懂度间接决定着用户之间的沟通品质。自 2011 年 WebRTC 开源以来,无论是其技术架构,还是其中丰盛的算法模块都是值得咱们细细品味,音频方面熟知的 3A 算法(AGC: Automatic gain control; ANS: Adaptive noise suppression; AEC: Acoustic echo cancellation)就是其中闪闪发光的明珠。本文章将联合实例全面解析 WebRTC AEC 的根本框架和基本原理,一起摸索回声打消的基本原理,技术难点以及优化方向。

作者:珞神,阿里云高级开发工程师,负责阿里云 RTC 音频研发

回声的造成

WebRTC 架构中上下行音频信号处理流程如图 1,音频 3A 次要集中在上行的发送端对发送信号顺次进行回声打消、降噪以及音量平衡(这里只探讨 AEC 的解决流程,如果是 AECM 的解决流程 ANS 会前置),AGC 会作为压限器作用在接收端对行将播放的音频信号进行限幅。

那么回声是怎么造成的呢?

如图 2 所示,A、B 两人在通信的过程中,咱们有如下定义:

  • x(n): 远端参考信号,即 A 端订阅的 B 端音频流,通常作为参考信号;
  • y(n): 回声信号,即扬声器播放信号 x(n) 后,被麦克风采集到的信号,此时通过房间混响以及麦克风采集的信号 y(n) 曾经不能等同于信号 x(n) 了, 咱们记线性叠加的局部为 y'(n), 非线性叠加的局部为 y”(n), y(n) = y'(n) + y”(n);
  • s(n): 麦克风采集的近端谈话人的语音信号,即咱们真正想提取并发送到远端的信号;
  • v(n):环境乐音,这部分信号会在 ANS 中被减弱;
  • d(n): 近端信号,即麦克风采集之后,3A 之前的原始信号,能够示意为:d(n) = s(n) + y(n) + v(n);
  • s'(n): 3A 之后的音频信号,即筹备通过编码发送到对端的信号。

WebRTC 音频引擎可能拿到的已知信号只有近端信号 d(n) 和远端参考信号 x(n)。

如果信号通过 A 端音频引擎失去 s'(n) 信号中仍然残留信号 y(n),那么 B 端就能听到本人回声或残留的尾音(回声克制不彻底留下的残留)。AEC 成果评估在理论状况中能够粗略分为如下几种状况(业余人员可依据利用场景、设施以及单双讲进一步细分):

回声打消的实质

在解析 WebRTC AEC 架构之前,咱们须要理解回声打消的实质是什么。音视频通话过程中,声音是传播信息的次要路径,因而从简单的录音信号中,通过信号处理的伎俩使得咱们要传递的信息:高保真、低延时、清晰可懂是始终以来谋求的指标。在我看来,回声打消,噪声克制和声源拆散同属于语音加强的领域,如果把噪声了解为狭义的噪声三者之间的关系如下图:

噪声克制须要精确预计出噪声信号,其中安稳噪声能够通过语音检测判断有话端与无话端的状态来动静更新噪声信号,进而参加降噪,罕用的伎俩是基于谱减法 (即在原始信号的根底上减去预计进去的噪声所占的成分) 的一系列改良办法,其成果依赖于对噪声信号预计的准确性。对于非安稳噪声,目前用的较多的就是基于递归神经网络的深度学习办法,很多 Windows 设施上都内置了基于多麦克风阵列的降噪的算法。成果上,为了保障音质,噪声克制容许噪声残留,只有比原始信号信噪比高,噪且听觉上失真无感知即可。

单声道的声源拆散技术起源于传说中的鸡尾酒会效应,是指人的一种听力抉择能力,在这种状况下,注意力集中在某一个人的谈话之中而疏忽背景中其余的对话或乐音。该效应揭示了人类听觉零碎中令人惊奇的能力,即咱们能够在噪声中谈话。科学家们始终在致力于用技术手段从单声道录音中拆散出各种成分,始终以来的难点,随着机器学习技术的利用,使得该技术缓缓变成了可能,然而较高的计算复杂度等起因,间隔 RTC 这种低延时零碎中的商用还是有一些间隔。

噪声克制与声源拆散都是单源输出,只须要近端采集信号即可,傲娇的回声打消须要同时输出近端信号与远端参考信号。有同学会问已知了远端参考信号,为什么不能用噪声克制办法解决呢,间接从频域减掉远端信号的频谱不就能够了吗?

上图中第一行为近端信号 s(n),曾经混合了近端人声和扬声器播放进去的远端信号,黄色框中曾经标出对齐之后的远端信号,其语音表白的内容统一,然而频谱和幅度 (显著通过扬声器放大之后声音能量很高) 均不统一,意思就是:参考的远端信号与扬声器播放进去的远端信号曾经是“同床异梦”了,与降噪的办法相结合也是不错的思路,然而间接套用降噪的办法显然会造成回声残留与双讲局部重大的克制。接下来,咱们来看看 WebRTC 科学家是怎么做的吧。

信号处理流程

WebRTC AEC 算法蕴含了延时调整策略,线性回声预计,非线性回声克制 3 个局部。回声打消实质上更像是音源拆散,咱们冀望从混合的近端信号中打消不须要的远端信号,保留近端人声发送到远端,然而 WebRTC 工程师们更偏向于将两个人交换的过程了解为一问一答的交替谈话,存在远近端同时间断谈话的状况并不多(即保单讲轻双讲)。

因而只须要辨别远近端谈话区域就能够通过一些伎俩打消绝大多数远端回声,至于双讲恢复能力 WebRTC AEC 算法提供了 {kAecNlpConservative, kAecNlpModerate, kAecNlpAggressive} 3 个模式,由低到高顺次代表不同的克制水平,远近端信号处理流程如图 4:

NLMS 自适应算法(上图中橙色局部)的使用旨在尽可能地打消信号 d(n) 中的线性局部回声,而残留的非线性回声信号会在非线性滤波(上图中紫色局部)局部中被打消,这两个模块是 Webrtc AEC 的外围模块。模块前后依赖,事实场景中远端信号 x(n) 由扬声器播放进去在被麦克风采集的过程中,同时蕴含了回声 y(n) 与近端信号 x(n) 的线性叠加和非线性叠加:须要打消线性回声的目标是为了增大近端信号 X(ω) 与滤波后果 E(ω) 之间的差别,计算相干性时差别就越大(近端信号靠近 1,而远端信号局部越靠近 0),更容易通过门限间接辨别近端帧与远端帧。非线性滤波局部中只须要依据检测的帧类型,调节克制系数,滤波打消回声即可。上面咱们联合实例剖析这套架构中的线性局部与非线性分。

线性滤波

线性回声 y'(n) 能够了解为是远端参考信号 x(n) 通过房间冲击响应之后的后果,线性滤波的实质也就是在预计一组滤波器使得 y'(n) 尽可能的等于 x(n),通过统计滤波器组的最大幅值地位 index 找到与之对齐远端信号帧,该帧数据会参加相干性计算等后续模块。

须要留神的是,如果 index 在滤波器阶数两端疯狂试探,只能阐明以后给到线性局部的远近端延时较小或过大,此时滤波器成果是不稳固的,须要借助固定延时调整或大延时调整使 index 处于一个比拟现实的地位。线性局部算法是能够看作是一个固定步长的 NLMS 算法,具体细节大家能够联合源码走读,本节重点解说线型滤波在整个框架中的作用。

从集体了解来看,线性局部的目标就是最大水平的打消线性回声,为远近端帧判断的时候,最大水平地保障了信号之间的相干值 (0~1 之间,值越大相干性越大) 的可靠性。

咱们记打消线性回声之后的信号为预计的回声信号 e(n),e(n) = s(n) + y”(n) + v(n),其中 y”(n) 为非线性回声信号,记 y'(n) 为线性回声,y(n) = y'(n) + y”(n)。相干性的计算(Matlab 代码):

% WebRtcAec_UpdateCoherenceSpectra →_→ UpdateCoherenceSpectra
Sd = Sd * ptrGCoh(1) + abs(wined_fft_near) .* abs(wined_fft_near)*ptrGCoh(2);
Se = Se * ptrGCoh(1) + abs(wined_fft_echo) .* abs(wined_fft_echo)*ptrGCoh(2);
Sx = Sx * ptrGCoh(1) + max(abs(wined_fft_far) .* abs(wined_fft_far),ones(N+1,1)*MinFarendPSD)*ptrGCoh(2);
Sde = Sde * ptrGCoh(1) + (wined_fft_near .* conj(wined_fft_echo)) *ptrGCoh(2);
Sxd = Sxd * ptrGCoh(1) + (wined_fft_near .* conj(wined_fft_far)) *ptrGCoh(2);     

% WebRtcAec_ComputeCoherence →_→ ComputeCoherence
cohde = (abs(Sde).*abs(Sde))./(Sd.*Se + 1.0e-10);
cohdx = (abs(Sxd).*abs(Sxd))./(Sx.*Sd + 1.0e-10);

两个试验

(1)计算近端信号 d(n) 与远端参考信号 x(n) 的相关性 cohdx,实践上远端回声信号的相干性应该更靠近 0(为了不便后续比照,WebRTC 做了反向解决: 1 – cohdx),如图 5(a),第一行为计算近端信号 d(n),第二行为远端参考信号 x(n),第三行为二者相干性曲线: 1 – cohdx,会发现回声局部相干值有显著起伏,最大值有 0.7,近端局部整体靠近 1.0,然而有继续稳定,如果想通过一条固定的门限去辨别远近端帧,会存在不同水平的误判,反映到听感上就是回声(远端判断成近端)或丢字(近端判断为远端)。

图 5 信号的相干性

(2)计算近端信号 d(n) 与预计的回声信号 e(n) 的相干性,如图 5(b),第二行为预计的回声信号 e(n),第三行为二者相干性 cohde,很显著近端的局部简直全副迫近 1.0,WebRTC 用比拟严格的门限(>=0.98)即可将辨别绝大部分近端帧,且误判的概率比拟小,WebRTC 工程师设置如此严格的门限想必是宁肯就义一部分双讲成果,也不违心承受回声残留。

从图 5 能够领会到,线性滤波之后能够进一步凸显远端参考信号 x(n) 与预计的回声信号 e(n) 的差别,从而进步远近端帧状态的裁决的可靠性。

存在的问题与改良

现实状况下,远端信号从扬声器播放进去没有非线性失真,那么 e(n) = s(n) + v(n),但理论状况下 e(n)与 d(n) 很像,只是远端区域有一些幅度上的变动,阐明 WebRTC AEC 线性局部在这个 case 中体现不佳,如图 6(a) 从频谱看低频段显著减弱,但中高频局部简直没变。而利用变步长的双滤波器构造的后果会非常明显,如图 6(b) 所示无论是时域波形和频谱与近端信号 x(n) 都有很大差别,目前 aec3 和 speex 中都采纳这种构造,可见 WebRTC AEC 中线性局部还有很大的优化空间。

图 6 近端信号与预计的回声信号的比照

如何掂量改良的线性局部成果?

这里咱们比照了现有的固定步长的 NLMS 和变步长的 NLMS,近端信号 d(n) 为加混响的远端参考信号 x(n) + 近端语音信号 s(n)。实践上 NLMS 在解决这种纯线性叠加的信号时,能够不必非线性局部出马,间接干掉远端回声信号。图 7(a) 第一行为近端信号 d(n),第二列为远端参考信号 x(n),线性局部输入后果,黄色框中为远端信号。WebRTC AEC 中采纳固定步长的 NLMS 算法收敛较慢,有些许回声残留。然而变步长的 NLMS 收敛较快,回声克制绝对好一些,如图 7(b)。

图 7 两种 NLMS 算法的成果比照

线性滤波器参数设置

#define FRAME_LEN 80
#define PART_LEN 64
enum {kExtendedNumPartitions = 32};
static const int kNormalNumPartitions = 12;

FRAME_LEN 为每次传给音频 3A 模块的数据的长度,默认为 80 个采样点,因为 WebRTC AEC 采纳了 128 点 FFT,外部拼帧逻辑会取出 PART_LEN = 64 个样本点与前一帧残余数据连接成 128 点做 FFT,残余的 16 点遗留到下一次,因而理论每次解决 PART_LEN 个样本点(4ms 数据)。

默认滤波器阶数仅为 kNormalNumPartitions = 12 个,可能笼罩的数据范畴为 kNormalNumPartitions 4ms = 48ms,如果关上扩大滤波器模式(设置 extended_filter_enabled 为 true),笼罩数据范畴为 kNormalNumPartitions 4ms = 132ms。随着芯片解决能力的晋升,默认会关上这个扩大滤波器模式,甚至扩大为更高的阶数,以此来应答市面上绝大多数的挪动设施。另外,线性滤波器尽管不具备调整延时的能力,但能够通过预计的 index 掂量以后信号的延时状态,范畴为 [0, kNormalNumPartitions],如果 index 处于作用域两端,阐明实在延时过小或过大,会影响线性回声预计的成果,重大的会带来回声,此时须要联合固定延时与大延时检测来修改。

非线性滤波

非线性局部一共做了两件事,就是想尽千方百计干掉远端信号。

(1) 依据线性局部提供的预计的回声信号,计算信号间的相干性,判断远近端帧状态。

(2) 调整克制系数,计算非线性滤波参数。

非线性滤波克制系数为 hNl,大抵表征着预计的回声信号 e(n) 中,冀望的近端成分与残留的非线性回声信号 y”(n) 在不同频带上的能量比,hNl 是与相干值是统一的,范畴是 [0,1.0],通过图 5(b) 能够看出须要打消的远端局部幅度值也广泛在 0.5 左右,如果间接应用 hNl 滤波会导致大量的回声残留。

因而 WebRTC 工程师对 hNl 做了如下尺度变换,over_drive 与 nlp_mode 相干,代表不同的克制激进水平,drive_curve 是一条枯燥递增的凸曲线,范畴 [1.0, 2.0]。因为中高频的尾音在听感上比拟显著,所以他们设计了这样的克制曲线来克制高频尾音。咱们记尺度变换的 α = over_drive_scaling * drive_curve,如果设置 nlp_mode = kAecNlpAggressive,α 大概会在 30 左右。

% matlab 代码如下:over_drive = min_override(nlp_mode+1);
if (over_drive < over_drive_scaling)
  over_drive_scaling = 0.99*over_drive_scaling + 0.01*over_drive;  % default 0.99 0.01
else
  over_drive_scaling = 0.9*over_drive_scaling + 0.1*over_drive; % default 0.9 0.1
end

% WebRtcAec_Overdrive →_→ Overdrive
hNl(index) = weight_curve(index).*hNlFb + (1-weight_curve(index)).* hNl(index);
hNl = hNl.^(over_drive_scaling * drive_curve);

% WebRtcAec_Suppress →_→ Suppress
wined_fft_echo = wined_fft_echo .*hNl;
wined_fft_echo = conj(wined_fft_echo);

如果以后帧为近端帧(即 echo_state = false),假如第 k 个频带 hNl(k) = 0.99994,hNl(k) = hNl(k)^α = 0.99994 ^ 30 = 0.9982,即便滤波后的损失听感上简直无感知。如图 8(a),hNl 通过 α 调制之后,幅值仍然很靠近 1.0。

如果以后帧为远端帧(即 echo_state = true),假如第 k 个频带 hNl(k) = 0.6676,hNl(k) = hNl(k)^α = 0.6676 ^ 30 = 5.4386e-06,滤波后远端能量小到根本听不到了。如图 8(b),hNl 通过 α 调制之后,根本靠近 0。

图 8 远近端信号克制系数在调制前后的变动

通过如上比照,为了保障通过调制之后近端冀望信号失真最小,远端回声能够被克制到不可听,WebRTC AEC 才在远近端帧状态判断的的模块中设置了如此严格的门限。

另外,调整系数 α 过于严格的状况下会带来双讲的克制,如图 9 第 1 行,近端谈话人声音显著失落,通过调整 α 后得以复原,如第 2 行所示。因而如果在 WebRTC AEC 现有策略上优化 α 预计,能够缓解双讲克制重大的问题。

延时调整策略

回声打消的成果与远近端数据延时强相干,调整不当会带来算法不可用的危险。在远近端数据进入线性局部之前,肯定要保障延时在设计的滤波器阶数范畴内,不然延时过大超出了线性滤波器预计的范畴或调整过当导致远近端非因果都会造成无奈收敛的回声。先科普两个问题:

(1)为什么会存在延时?

首先近端信号 d(n) 中的回声是扬声器播放远端参考 x(n),又被麦克风采集到的造成的,也就意味着在近端数据还未采集进来之前,远端数据缓冲区中曾经躺着 N 帧 x(n)了,这个人造的延时能够约等于音频信号从筹备渲染到被麦克风采集到的工夫,不同设施这个延时是不等的。苹果设施延时较小,根本在 120ms 左右,Android 设施广泛在 200ms 左右,低端机型上会有 300ms 左右甚至以上。

(2)远近端非因果为什么会导致回声?

从(1)中能够认为,失常状况下以后帧近端信号为了找到与之对齐的远端信号,必须在远端缓冲区沿着写指针向前查找。如果此时设施采集丢数据,远端数据会迅速耗费,导致新来的近端帧在向前查找时,曾经找不到与之对齐的远端参考帧了,会导致后续各模块工作异样。如图 10(a) 示意失常延时状况,(b) 示意非因果。

图 10 失常远近端延时与非因果

WebRTC AEC 中的延时调整策略要害而且简单,波及到固定延时调整,大延时检测,以及线性滤波器延时预计。三者的关系如下:

① 固定延时调整只会产生在开始 AEC 算法开始解决之前,而且仅调整一次。如会议盒子等固定的硬件设施延时根本是固定的,能够通过间接减去固定的延时的办法放大延时预计范畴,使之疾速来到滤波器笼罩的延时范畴之内。
上面联合代码来看看固定延时的调整过程:

int32_t WebRtcAec_Process(void* aecInst,
const float* const* nearend,
size_t num_bands,
float* const* out,
size_t nrOfSamples,
int16_t reported_delay_ms,
int32_t skew);

WebRtcAec_Process 接口如上,参数 reported_delay_ms 为以后设施须要调整延时的目标值。如某 Android 设施固定延时为 400ms 左右,400ms 曾经超出滤波器笼罩的延时范畴,至多须要调整 300ms 延时,能力满足回声打消没有回声的要求。固定延时调整在 WebRTC AEC 算法开始之初仅作用一次:

if (self->startup_phase) {
    int startup_size_ms = reported_delay_ms < kFixedDelayMs ? kFixedDelayMs : reported_delay_ms;
    int target_delay = startup_size_ms * self->rate_factor * 8;
    int overhead_elements = (WebRtcAec_system_delay_aliyun(self->aec) - target_delay) / PART_LEN;
    printf("target_delay = %d, startup_size_ms = %d, self->rate_factor = %d, sysdelay = %d, overhead_elements = %d\n", target_delay, startup_size_ms, self->rate_factor, WebRtcAec_system_delay(self->aec), overhead_elements);
    WebRtcAec_AdjustFarendBufferSizeAndSystemDelay_aliyun(self->aec,  overhead_elements);
self->startup_phase = 0;
  }

为什么 target_delay 是这么计算?

int target_delay = startup_size_ms self->rate_factor 8;
startup_size_ms 其实就是设置上来的 reported_delay_ms,这一步将计算工夫毫秒转化为样本点数。16000hz 采样中,10ms 示意 160 个样本点,因而 target_delay 理论就是须要调整的指标样本点数(aecpc->rate_factor = aecpc->splitSampFreq / 8000 = 2)。

咱们用 330ms 延时的数据测试:
如果设置默认延时为 240ms,overhead_elements 第一次被调整了 -60 个 block,负值示意向前查找,正好为 60 4 = 240ms,之后线性滤波器固定 index = 24,示意 24 4 = 96ms 延时,二者之和约等于 330ms。日志打印如下:

② 大延时检测是基于远近端数据相似性在远端大缓存中查找最类似的帧的过程,其算法原理有点相似音频指纹中特色匹配的思维。大延时调整的能力是对固定延时调整与线型滤波器能力的补充,应用它的时候须要比拟谨慎,须要管制调整的频率,以及管制造成非因果的危险。

WebRTC AEC 算法中开拓了可存储 250 个 block 大缓冲区,每个 block 的长度 PART_LEN = 64 个样本点,可能保留最新的 1s 的数据,这也是实践上的大延时可能预计的范畴,相对够用了。

static const size_t kBufferSizeBlocks = 250;
buffer_ = WebRtc_CreateBuffer(kBufferSizeBlocks, sizeof(float) * PART_LEN);
aec->delay_agnostic_enabled = 1;

咱们用 610ms 延时的数据测试 (启用大延时调整须要设置 delay_agnostic_enabled = 1):
咱们还是设置默认延时为 240ms,刚开始还是调整了 -60 个 block,随后大延时调整接入之后有调整了 -88 个 block,一共调整(60 + 88) * 4 = 592ms,之后线性滤波器固定 index = 4,示意最初残余延时残余 16ms,合乎预期。

③ 线性滤波器延时预计是固定延时调整和大延时调整之后,滤波器对以后远近端延时的最间接反馈。前两者调整不当会造成延时过小甚至非因果,或延时过大超出滤波器笼罩能力,导致无奈收敛的回声。因而前两者在调整的过程中须要联合滤波器的能力,确保残余延时在滤波器可能笼罩的范畴之内,即便延时小范畴抖动,线性局部也能自适应调整。

总结与优化方向

WebRTC AEC 存在的问题:

(1)线性局部收敛工夫较慢,固定步长的 NLMS 算法对线性局部回声的预计欠佳;
(2)线性局部滤波器阶数默认为 32 阶,默认笼罩延时 132ms,对挪动端延时较大设施反对不是很好,大延时检测局部染指较慢,且存在误调导致非因果回声的危险;
(3)基于相干性的帧状态依赖严格的固定门限,存在肯定水平的误判,如果再去领导非线性局部克制系数的调节,会带来比较严重的双讲克制。

优化的方向:
(1)算法上能够通过学习 speex 和 AEC3 的线性局部,改善以后线性滤波成果;
(2)算法上能够优化延时调整策略,工程上能够新增参数配置下发等工程伎俩解决一些设施的延时问题;
(3)另外,有一些新的思路也是值得咱们尝试的,如结尾提到的,既然回声也能够是视为噪声,那么是否用降噪的思路做回声打消呢,答案是能够的。

「视频云技术」你最值得关注的音视频技术公众号,每周推送来自阿里云一线的实际技术文章,在这里与音视频畛域一流工程师交换切磋。

退出移动版