Added forced zero AEC output after call startup and echo path changes
During the first few capture frames, there is no way for the AEC
to tell whether there is echo in the capture signal as the echo
removal functionality in the AEC has not yet seen any render
signal. To avoid initial echo bursts due to this, this CL adds
functionality for forcing the echo suppression gain to zero during
the first 50 blocks (200 ms) after call start and after a reported
echo path change.
BUG=webrtc:6018
Review-Url: https://codereview.webrtc.org/2808733002
Cr-Original-Commit-Position: refs/heads/master@{#17624}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 6d822adac4439258b0a07c5458620fcf2314874f
diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc
index 8e92f5f..1a9f66f 100644
--- a/modules/audio_processing/aec3/aec_state.cc
+++ b/modules/audio_processing/aec3/aec_state.cc
@@ -97,6 +97,11 @@
echo_saturation_ = false;
headset_detected_ = false;
previous_max_sample_ = 0.f;
+
+ if (echo_path_variability.delay_change) {
+ force_zero_gain_counter_ = 0;
+ force_zero_gain_ = true;
+ }
}
}
@@ -117,6 +122,12 @@
active_render_blocks_ += active_render_block ? 1 : 0;
--echo_path_change_counter_;
+ // Force zero echo suppression gain after an echo path change to allow at
+ // least some render data to be collected in order to avoid an initial echo
+ // burst.
+ constexpr size_t kZeroGainBlocksAfterChange = kNumBlocksPerSecond / 5;
+ force_zero_gain_ = (++force_zero_gain_counter_) < kZeroGainBlocksAfterChange;
+
// Estimate delays.
filter_delay_ = EstimateFilterDelay(adaptive_filter_frequency_response);
external_delay_ =
diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h
index 00b6252..387c6ea 100644
--- a/modules/audio_processing/aec3/aec_state.h
+++ b/modules/audio_processing/aec3/aec_state.h
@@ -80,6 +80,9 @@
// TODO(peah): Make this adaptive.
float ReverbDecayFactor() const { return 0.f; }
+ // Returns whether the echo suppression gain should be forced to zero.
+ bool ForcedZeroGain() const { return force_zero_gain_; }
+
// Updates the aec state.
void Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>&
adaptive_filter_frequency_response,
@@ -103,6 +106,8 @@
bool echo_saturation_ = false;
bool headset_detected_ = false;
float previous_max_sample_ = 0.f;
+ bool force_zero_gain_ = false;
+ size_t force_zero_gain_counter_ = 0;
rtc::Optional<size_t> filter_delay_;
rtc::Optional<size_t> external_delay_;
size_t blocks_since_last_saturation_ = 1000;
diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc
index 2b28a21..ea40253 100644
--- a/modules/audio_processing/aec3/echo_remover.cc
+++ b/modules/audio_processing/aec3/echo_remover.cc
@@ -182,7 +182,7 @@
// A choose and apply echo suppression gain.
suppression_gain_.GetGain(E2, R2, cng_.NoiseSpectrum(),
aec_state_.SaturatedEcho(), x, y->size(),
- &high_bands_gain, &G);
+ aec_state_.ForcedZeroGain(), &high_bands_gain, &G);
suppression_filter_.ApplyGain(comfort_noise, high_band_comfort_noise, G,
high_bands_gain, y);
diff --git a/modules/audio_processing/aec3/suppression_gain.cc b/modules/audio_processing/aec3/suppression_gain.cc
index 0e50292..4bf452c 100644
--- a/modules/audio_processing/aec3/suppression_gain.cc
+++ b/modules/audio_processing/aec3/suppression_gain.cc
@@ -325,11 +325,21 @@
bool saturated_echo,
const std::vector<std::vector<float>>& render,
size_t num_capture_bands,
+ bool force_zero_gain,
float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain) {
RTC_DCHECK(high_bands_gain);
RTC_DCHECK(low_band_gain);
+ if (force_zero_gain) {
+ previous_gain_squared_.fill(0.f);
+ std::copy(comfort_noise_power.begin() + 1, comfort_noise_power.end() - 1,
+ previous_masker_.begin());
+ low_band_gain->fill(0.f);
+ *high_bands_gain = 0.f;
+ return;
+ }
+
// Choose margin to use.
const float margin = saturated_echo ? 0.001f : 0.01f;
switch (optimization_) {
diff --git a/modules/audio_processing/aec3/suppression_gain.h b/modules/audio_processing/aec3/suppression_gain.h
index 6b36a63..d0b4114 100644
--- a/modules/audio_processing/aec3/suppression_gain.h
+++ b/modules/audio_processing/aec3/suppression_gain.h
@@ -52,6 +52,7 @@
bool saturated_echo,
const std::vector<std::vector<float>>& render,
size_t num_capture_bands,
+ bool force_zero_gain,
float* high_bands_gain,
std::array<float, kFftLengthBy2Plus1>* low_band_gain);
diff --git a/modules/audio_processing/aec3/suppression_gain_unittest.cc b/modules/audio_processing/aec3/suppression_gain_unittest.cc
index f4feb74..83c41e1 100644
--- a/modules/audio_processing/aec3/suppression_gain_unittest.cc
+++ b/modules/audio_processing/aec3/suppression_gain_unittest.cc
@@ -33,7 +33,7 @@
.GetGain(E2, R2, N2, false,
std::vector<std::vector<float>>(
3, std::vector<float>(kBlockSize, 0.f)),
- 1, &high_bands_gain, nullptr),
+ 1, false, &high_bands_gain, nullptr),
"");
}
@@ -128,7 +128,8 @@
R2.fill(0.1f);
N2.fill(100.f);
for (int k = 0; k < 10; ++k) {
- suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
+ suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
+ &g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
@@ -138,7 +139,8 @@
R2.fill(0.1f);
N2.fill(0.f);
for (int k = 0; k < 10; ++k) {
- suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
+ suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
+ &g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(1.f, a, 0.001); });
@@ -148,10 +150,16 @@
R2.fill(100.f);
N2.fill(0.f);
for (int k = 0; k < 10; ++k) {
- suppression_gain.GetGain(E2, R2, N2, false, x, 1, &high_bands_gain, &g);
+ suppression_gain.GetGain(E2, R2, N2, false, x, 1, false, &high_bands_gain,
+ &g);
}
std::for_each(g.begin(), g.end(),
[](float a) { EXPECT_NEAR(0.f, a, 0.001); });
+
+ // Verify the functionality for forcing a zero gain.
+ suppression_gain.GetGain(E2, R2, N2, false, x, 1, true, &high_bands_gain, &g);
+ std::for_each(g.begin(), g.end(), [](float a) { EXPECT_FLOAT_EQ(0.f, a); });
+ EXPECT_FLOAT_EQ(0.f, high_bands_gain);
}
} // namespace aec3