AEC3: Transparency improvements to the suppressor

This CL contains changes to the echo suppressor that improves the
transparency of AEC3.

- The comfort noise level is used as masker and the masking threshold is
increased.
- Suppression gains are allowed to increase more rapidly.
- Suppression gains decrease slower in the lower frequencies after strong
nearend.

Change-Id: I7adf31ed90b0e007072191f40439f27c3b0bccf2
Bug: webrtc:9230,chromium:839379
Reviewed-on: https://webrtc-review.googlesource.com/73680
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23115}
This commit is contained in:
Gustaf Ullberg
2018-05-04 11:29:02 +02:00
committed by Commit Bot
parent 35b67f0710
commit 0e6375e78b
4 changed files with 62 additions and 12 deletions

View File

@ -116,6 +116,7 @@ rtc_static_library("aec3") {
"../../../rtc_base:rtc_base_approved",
"../../../rtc_base:safe_minmax",
"../../../system_wrappers:cpu_features_api",
"../../../system_wrappers:field_trial_api",
"../../../system_wrappers:metrics_api",
]

View File

@ -24,10 +24,16 @@
#include "modules/audio_processing/logging/apm_data_dumper.h"
#include "rtc_base/atomicops.h"
#include "rtc_base/checks.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace {
bool EnableTransparencyImprovements() {
return !field_trial::IsEnabled(
"WebRTC-Aec3TransparencyImprovementsKillSwitch");
}
// Adjust the gains according to the presence of known external filters.
void AdjustForExternalFilters(std::array<float, kFftLengthBy2Plus1>* gain) {
// Limit the low frequency gains to avoid the impact of the high-pass filter
@ -148,6 +154,7 @@ void GainToNoAudibleEcho(
bool low_noise_render,
bool saturated_echo,
bool linear_echo_estimate,
bool enable_transparency_improvements,
const std::array<float, kFftLengthBy2Plus1>& nearend,
const std::array<float, kFftLengthBy2Plus1>& weighted_echo,
const std::array<float, kFftLengthBy2Plus1>& masker,
@ -169,7 +176,10 @@ void GainToNoAudibleEcho(
RTC_DCHECK_GT(1.f, nearend_masking_margin);
const float masker_margin =
linear_echo_estimate ? config.gain_mask.m1 : config.gain_mask.m8;
linear_echo_estimate
? (enable_transparency_improvements ? config.gain_mask.m0
: config.gain_mask.m1)
: config.gain_mask.m8;
for (size_t k = 0; k < gain->size(); ++k) {
const float unity_gain_masker = std::max(nearend[k], masker[k]);
@ -196,11 +206,17 @@ constexpr size_t kUpperAccurateBandPlus1 = 29;
// Computes the signal output power that masks the echo signal.
void MaskingPower(const EchoCanceller3Config& config,
bool enable_transparency_improvements,
const std::array<float, kFftLengthBy2Plus1>& nearend,
const std::array<float, kFftLengthBy2Plus1>& comfort_noise,
const std::array<float, kFftLengthBy2Plus1>& last_masker,
const std::array<float, kFftLengthBy2Plus1>& gain,
std::array<float, kFftLengthBy2Plus1>* masker) {
if (enable_transparency_improvements) {
std::copy(comfort_noise.begin(), comfort_noise.end(), masker->begin());
return;
}
// Apply masking over time.
float masking_factor = config.gain_mask.temporal_masking_lf;
auto limit = config.gain_mask.temporal_masking_lf_bands;
@ -286,6 +302,18 @@ void SuppressionGain::LowerBandGain(
min_gain[k] = denom > 0.f ? min_echo_power / denom : 1.f;
min_gain[k] = std::min(min_gain[k], 1.f);
}
if (enable_transparency_improvements_) {
for (size_t k = 0; k < 6; ++k) {
// Make sure the gains of the low frequencies do not decrease too
// quickly after strong nearend.
if (last_nearend_[k] > last_echo_[k]) {
min_gain[k] =
std::max(min_gain[k],
last_gain_[k] * config_.gain_updates.max_dec_factor_lf);
min_gain[k] = std::min(min_gain[k], 1.f);
}
}
}
} else {
min_gain.fill(0.f);
}
@ -293,10 +321,20 @@ void SuppressionGain::LowerBandGain(
// Compute the maximum gain by limiting the gain increase from the previous
// gain.
std::array<float, kFftLengthBy2Plus1> max_gain;
for (size_t k = 0; k < gain->size(); ++k) {
max_gain[k] = std::min(std::max(last_gain_[k] * gain_increase_[k],
config_.gain_updates.floor_first_increase),
1.f);
if (enable_transparency_improvements_) {
for (size_t k = 0; k < gain->size(); ++k) {
max_gain[k] =
std::min(std::max(last_gain_[k] * config_.gain_updates.max_inc_factor,
config_.gain_updates.floor_first_increase),
1.f);
}
} else {
for (size_t k = 0; k < gain->size(); ++k) {
max_gain[k] =
std::min(std::max(last_gain_[k] * gain_increase_[k],
config_.gain_updates.floor_first_increase),
1.f);
}
}
// Iteratively compute the gain required to attenuate the echo to a non
@ -304,10 +342,12 @@ void SuppressionGain::LowerBandGain(
gain->fill(0.f);
std::array<float, kFftLengthBy2Plus1> masker;
for (int k = 0; k < 2; ++k) {
MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain, &masker);
MaskingPower(config_, enable_transparency_improvements_, nearend,
comfort_noise, last_masker_, *gain, &masker);
GainToNoAudibleEcho(config_, low_noise_render, saturated_echo,
linear_echo_estimate, nearend, weighted_echo, masker,
min_gain, max_gain, one_by_weighted_echo, gain);
linear_echo_estimate, enable_transparency_improvements_,
nearend, weighted_echo, masker, min_gain, max_gain,
one_by_weighted_echo, gain);
AdjustForExternalFilters(gain);
}
@ -319,10 +359,11 @@ void SuppressionGain::LowerBandGain(
weighted_echo, *gain);
// Store data required for the gain computation of the next block.
std::copy(nearend.begin(), nearend.end(), last_nearend_.begin());
std::copy(weighted_echo.begin(), weighted_echo.end(), last_echo_.begin());
std::copy(gain->begin(), gain->end(), last_gain_.begin());
MaskingPower(config_, nearend, comfort_noise, last_masker_, *gain,
&last_masker_);
MaskingPower(config_, enable_transparency_improvements_, nearend,
comfort_noise, last_masker_, *gain, &last_masker_);
aec3::VectorMath(optimization_).Sqrt(*gain);
// Debug outputs for the purpose of development and analysis.
@ -342,12 +383,14 @@ SuppressionGain::SuppressionGain(const EchoCanceller3Config& config,
state_change_duration_blocks_(
static_cast<int>(config_.filter.config_change_duration_blocks)),
coherence_gain_(sample_rate_hz,
config_.suppressor.bands_with_reliable_coherence) {
config_.suppressor.bands_with_reliable_coherence),
enable_transparency_improvements_(EnableTransparencyImprovements()) {
RTC_DCHECK_LT(0, state_change_duration_blocks_);
one_by_state_change_duration_blocks_ = 1.f / state_change_duration_blocks_;
last_gain_.fill(1.f);
last_masker_.fill(0.f);
gain_increase_.fill(1.f);
last_nearend_.fill(0.f);
last_echo_.fill(0.f);
}
@ -376,7 +419,8 @@ void SuppressionGain::GetGain(
comfort_noise_spectrum, low_band_gain);
// Adjust the gain for bands where the coherence indicates not echo.
if (config_.suppressor.bands_with_reliable_coherence > 0) {
if (config_.suppressor.bands_with_reliable_coherence > 0 &&
!enable_transparency_improvements_) {
std::array<float, kFftLengthBy2Plus1> G_coherence;
coherence_gain_.ComputeGain(linear_aec_fft, render_fft, capture_fft,
G_coherence);

View File

@ -78,11 +78,13 @@ class SuppressionGain {
std::array<float, kFftLengthBy2Plus1> last_gain_;
std::array<float, kFftLengthBy2Plus1> last_masker_;
std::array<float, kFftLengthBy2Plus1> gain_increase_;
std::array<float, kFftLengthBy2Plus1> last_nearend_;
std::array<float, kFftLengthBy2Plus1> last_echo_;
LowNoiseRenderDetector low_render_detector_;
bool initial_state_ = true;
int initial_state_change_counter_ = 0;
CoherenceGain coherence_gain_;
const bool enable_transparency_improvements_;
RTC_DISALLOW_COPY_AND_ASSIGN(SuppressionGain);
};