diff --git a/webrtc/modules/audio_processing/aec3/aec_state.cc b/webrtc/modules/audio_processing/aec3/aec_state.cc index 8e92f5fbda..1a9f66ffcb 100644 --- a/webrtc/modules/audio_processing/aec3/aec_state.cc +++ b/webrtc/modules/audio_processing/aec3/aec_state.cc @@ -97,6 +97,11 @@ void AecState::HandleEchoPathChange( 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 @@ void AecState::Update(const std::vector>& 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/webrtc/modules/audio_processing/aec3/aec_state.h b/webrtc/modules/audio_processing/aec3/aec_state.h index 00b62529f6..387c6ea42d 100644 --- a/webrtc/modules/audio_processing/aec3/aec_state.h +++ b/webrtc/modules/audio_processing/aec3/aec_state.h @@ -80,6 +80,9 @@ class AecState { // 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>& adaptive_filter_frequency_response, @@ -103,6 +106,8 @@ class AecState { 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 filter_delay_; rtc::Optional external_delay_; size_t blocks_since_last_saturation_ = 1000; diff --git a/webrtc/modules/audio_processing/aec3/echo_remover.cc b/webrtc/modules/audio_processing/aec3/echo_remover.cc index 2b28a21751..ea4025365a 100644 --- a/webrtc/modules/audio_processing/aec3/echo_remover.cc +++ b/webrtc/modules/audio_processing/aec3/echo_remover.cc @@ -182,7 +182,7 @@ void EchoRemoverImpl::ProcessCapture( // 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/webrtc/modules/audio_processing/aec3/suppression_gain.cc b/webrtc/modules/audio_processing/aec3/suppression_gain.cc index 0e50292008..4bf452cbbe 100644 --- a/webrtc/modules/audio_processing/aec3/suppression_gain.cc +++ b/webrtc/modules/audio_processing/aec3/suppression_gain.cc @@ -325,11 +325,21 @@ void SuppressionGain::GetGain( bool saturated_echo, const std::vector>& render, size_t num_capture_bands, + bool force_zero_gain, float* high_bands_gain, std::array* 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/webrtc/modules/audio_processing/aec3/suppression_gain.h b/webrtc/modules/audio_processing/aec3/suppression_gain.h index 6b36a63399..d0b4114393 100644 --- a/webrtc/modules/audio_processing/aec3/suppression_gain.h +++ b/webrtc/modules/audio_processing/aec3/suppression_gain.h @@ -52,6 +52,7 @@ class SuppressionGain { bool saturated_echo, const std::vector>& render, size_t num_capture_bands, + bool force_zero_gain, float* high_bands_gain, std::array* low_band_gain); diff --git a/webrtc/modules/audio_processing/aec3/suppression_gain_unittest.cc b/webrtc/modules/audio_processing/aec3/suppression_gain_unittest.cc index f4feb74a77..83c41e1254 100644 --- a/webrtc/modules/audio_processing/aec3/suppression_gain_unittest.cc +++ b/webrtc/modules/audio_processing/aec3/suppression_gain_unittest.cc @@ -33,7 +33,7 @@ TEST(SuppressionGain, NullOutputGains) { .GetGain(E2, R2, N2, false, std::vector>( 3, std::vector(kBlockSize, 0.f)), - 1, &high_bands_gain, nullptr), + 1, false, &high_bands_gain, nullptr), ""); } @@ -128,7 +128,8 @@ TEST(SuppressionGain, BasicGainComputation) { 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 @@ TEST(SuppressionGain, BasicGainComputation) { 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 @@ TEST(SuppressionGain, BasicGainComputation) { 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