在最新的WebRTC中
https://webrtc.googlesource.com/src/+/refs/heads/masterwebrtc.googlesource.com回声消除模块已经完全被aec2代替,和前一版本比较,变化最大的主要是非线性回声抑制模块。关于aec2中的非线性回声抑制内容,我将会在后面找时间慢慢更新。今天主要分享一下上一版本中aec模块中的非线性抑制代码,核心代码位于
https://github.com/python-leo/webrtc_audio_processing/blob/master/webrtc/modules/audio_processing/aec/aec_core.cgithub.com中的NonLinearProcessing函数中。这个模块中的难点再于控制逻辑,其他计算过程基本上都简单。我就一些关键的地方,分享一下我个人的想法,欢迎大家指导交流。
hNlXdAvg 表示参考信号与mic接收信号的不相关性;
hNlDeAvg 表示aec输出信号与mic接收信号的相关性。
/*主要用于更新hNlXdAvg的最小值hNlXdAvgMin。数值0.75控制了该更新的频率,如果或者数值越大,表面hNlXdAvgMin的更新频率越快,对残留回声也会越敏感*/
if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) {
aec->hNlXdAvgMin = hNlXdAvg;
}
if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) {
/*aec输出信号与mic接收信号相关性大,同时参考信号与mic接收信号的不相关性较大,说明此时只有近端信号,或者残留信号非常弱*/
aec->stNearState = 1;
} else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) {
/*aec输出信号与mic接收信号相关性较小,或者参考信号与mic接收信号的不相关性较小(相关性较大),说明此时存在残留回声需要抑制*/
aec->stNearState = 0;
}
if (aec->hNlXdAvgMin == 1)
/* 说明一段时间内的hNlXdAvgMin一直没有更新,也即hNlXdAvg较大(这里大于0.75),说明在较长的时间内,参考信号与mic接收信号的相关性较弱,也即回声残留程度较小*/
/*检测一段时间内是否出现了更小的hNlFbMin,hNlFbMin用来更新overd的抑制程度。数值0.6用来控制参数更新频率,该数值越大hNlFbMin更新越频繁,对于残留回声会越敏感*/
if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) {
aec->hNlFbLocalMin = hNlFbLow;
aec->hNlFbMin = hNlFbLow;
aec->hNlNewMin = 1;
aec->hNlMinCtr = 0;
}
/*以下两个参数以固定的步长更新,为的是hNlXdAvgMin与hNlFbMin不会陷入死锁状态无法更新。当然这里的步长因子也可以控制上述两个数值的更新频率,一般是步长因子越大更新越频繁*/
aec->hNlFbLocalMin =WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1);
aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1);
/*hNlMinCtr == 2表明hNlFbMin只在当前帧更新,而下一帧不更新。也即,当前帧找到最小数值需要连续满足hnlMinCtr - 1帧,防止误触发*/
if (aec->hNlMinCtr == 2) {
aec->hNlNewMin = 0;
aec->hNlMinCtr = 0;
/*kTargetSupp[aec->nlp_mode]用来设置当前帧抑制多少dB*/
aec->overDrive =WEBRTC_SPL_MAX(kTargetSupp[aec->nlp_mode] /
((float)log(aec->hNlFbMin + 1e-10f) + 1e-10f),min_overdrive[aec->nlp_mode]);
}