From 12eb85881c865a67be07d04856383fea22890d6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Per=20=C3=85hgren?= Date: Tue, 6 Mar 2018 10:40:51 +0100 Subject: [PATCH] Separating the AEC3 suppressor gain rampup behavior for call startup and in-call resets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This CL introduces a different rampup behavir for the call startup and after resets that may occur due to delay changes, clock-drift and audio path glitches. Bug: chromium:819111, webrtc:8979 Change-Id: Ied1d7896be7f0c69aa6deb61475117021ca6ab09 Reviewed-on: https://webrtc-review.googlesource.com/60002 Reviewed-by: Gustaf Ullberg Reviewed-by: Jesus de Vicente Pena Commit-Queue: Per Ã…hgren Cr-Commit-Position: refs/heads/master@{#22312} --- modules/audio_processing/aec3/BUILD.gn | 2 + modules/audio_processing/aec3/aec_state.cc | 39 ++------- modules/audio_processing/aec3/aec_state.h | 9 +- .../aec3/suppression_gain_limiter.cc | 83 +++++++++++++++++++ .../aec3/suppression_gain_limiter.h | 49 +++++++++++ 5 files changed, 144 insertions(+), 38 deletions(-) create mode 100644 modules/audio_processing/aec3/suppression_gain_limiter.cc create mode 100644 modules/audio_processing/aec3/suppression_gain_limiter.h diff --git a/modules/audio_processing/aec3/BUILD.gn b/modules/audio_processing/aec3/BUILD.gn index a1fc0e0743..03202fa29e 100644 --- a/modules/audio_processing/aec3/BUILD.gn +++ b/modules/audio_processing/aec3/BUILD.gn @@ -88,6 +88,8 @@ rtc_static_library("aec3") { "suppression_filter.h", "suppression_gain.cc", "suppression_gain.h", + "suppression_gain_limiter.cc", + "suppression_gain_limiter.h", "vector_buffer.cc", "vector_buffer.h", "vector_math.h", diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index 7818ff77a4..533290c893 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -63,7 +63,8 @@ AecState::AecState(const EchoCanceller3Config& config) config_(config), max_render_(config_.filter.main.length_blocks, 0.f), reverb_decay_(fabsf(config_.ep_strength.default_len)), - gain_rampup_increase_(ComputeGainRampupIncrease(config_)) {} + gain_rampup_increase_(ComputeGainRampupIncrease(config_)), + suppression_gain_limiter_(config_) {} AecState::~AecState() = default; @@ -83,6 +84,7 @@ void AecState::HandleEchoPathChange( render_received_ = false; blocks_with_active_render_ = 0; initial_state_ = true; + suppression_gain_limiter_.Reset(); }; // TODO(peah): Refine the reset scheme according to the type of gain and @@ -96,7 +98,6 @@ void AecState::HandleEchoPathChange( full_reset(); } else if (echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kBufferFlush) { - active_render_seen_ = false; full_reset(); } else if (echo_path_variability.delay_change != EchoPathVariability::DelayAdjustment::kDelayReset) { @@ -136,7 +137,7 @@ void AecState::Update( // Update the limit on the echo suppression after an echo path change to avoid // an initial echo burst. - UpdateSuppressorGainLimit(render_buffer.GetRenderActivity()); + suppression_gain_limiter_.Update(render_buffer.GetRenderActivity()); // Update the ERL and ERLE measures. if (converged_filter && capture_block_counter_ >= 2 * kNumBlocksPerSecond) { @@ -360,6 +361,7 @@ void AecState::UpdateReverb(const std::vector& impulse_response) { data_dumper_->DumpRaw("aec3_reverb_decay", reverb_decay_); data_dumper_->DumpRaw("aec3_reverb_tail_energy", tail_energy_); + data_dumper_->DumpRaw("aec3_suppression_gain_limit", SuppressionGainLimit()); } bool AecState::DetectActiveRender(rtc::ArrayView x) const { @@ -369,37 +371,6 @@ bool AecState::DetectActiveRender(rtc::ArrayView x) const { kFftLengthBy2; } -// Updates the suppressor gain limit. -void AecState::UpdateSuppressorGainLimit(bool render_activity) { - const auto& rampup_conf = config_.echo_removal_control.gain_rampup; - if (!active_render_seen_ && render_activity) { - active_render_seen_ = true; - realignment_counter_ = rampup_conf.full_gain_blocks; - } else if (realignment_counter_ > 0) { - --realignment_counter_; - } - - if (realignment_counter_ <= 0) { - suppressor_gain_limit_ = 1.f; - return; - } - - if (realignment_counter_ > rampup_conf.non_zero_gain_blocks) { - suppressor_gain_limit_ = 0.f; - return; - } - - if (realignment_counter_ == rampup_conf.non_zero_gain_blocks) { - suppressor_gain_limit_ = rampup_conf.first_non_zero_gain; - return; - } - - RTC_DCHECK_LT(0.f, suppressor_gain_limit_); - suppressor_gain_limit_ = - std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_); - RTC_DCHECK_GE(1.f, suppressor_gain_limit_); -} - bool AecState::DetectEchoSaturation(rtc::ArrayView x) { RTC_DCHECK_LT(0, x.size()); const float max_sample = fabs(*std::max_element( diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index 56e6c3695e..6dcd43d79b 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -26,6 +26,7 @@ #include "modules/audio_processing/aec3/erl_estimator.h" #include "modules/audio_processing/aec3/erle_estimator.h" #include "modules/audio_processing/aec3/render_buffer.h" +#include "modules/audio_processing/aec3/suppression_gain_limiter.h" #include "rtc_base/constructormagic.h" namespace webrtc { @@ -91,7 +92,9 @@ class AecState { float ReverbDecay() const { return reverb_decay_; } // Returns the upper limit for the echo suppression gain. - float SuppressionGainLimit() const { return suppressor_gain_limit_; } + float SuppressionGainLimit() const { + return suppression_gain_limiter_.Limit(); + } // Returns whether the echo in the capture signal is audible. bool InaudibleEcho() const { return echo_audibility_.InaudibleEcho(); } @@ -156,9 +159,6 @@ class AecState { bool transparent_mode_ = false; float previous_max_sample_ = 0.f; bool render_received_ = false; - int realignment_counter_ = 0; - float suppressor_gain_limit_ = 1.f; - bool active_render_seen_ = false; int filter_delay_ = 0; size_t blocks_since_last_saturation_ = 1000; float tail_energy_ = 0.f; @@ -179,6 +179,7 @@ class AecState { bool filter_has_had_time_to_converge_ = false; bool initial_state_ = true; const float gain_rampup_increase_; + SuppressionGainUpperLimiter suppression_gain_limiter_; RTC_DISALLOW_COPY_AND_ASSIGN(AecState); }; diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.cc b/modules/audio_processing/aec3/suppression_gain_limiter.cc new file mode 100644 index 0000000000..643bb5803b --- /dev/null +++ b/modules/audio_processing/aec3/suppression_gain_limiter.cc @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/audio_processing/aec3/suppression_gain_limiter.h" + +#include +#include + +#include "modules/audio_processing/aec3/aec3_common.h" + +namespace webrtc { +namespace { + +// Computes the gain rampup factor to use. +float ComputeGainRampupIncrease( + const EchoCanceller3Config::EchoRemovalControl::GainRampup& rampup_config) { + return powf(1.f / rampup_config.first_non_zero_gain, + 1.f / rampup_config.non_zero_gain_blocks); +} + +} // namespace + +SuppressionGainUpperLimiter::SuppressionGainUpperLimiter( + const EchoCanceller3Config& config) + : rampup_config_(config.echo_removal_control.gain_rampup), + gain_rampup_increase_(ComputeGainRampupIncrease(rampup_config_)) { + Reset(); +} + +void SuppressionGainUpperLimiter::Reset() { + recent_reset_ = true; +} + +void SuppressionGainUpperLimiter::Update(bool render_activity) { + if (recent_reset_ && !call_startup_phase_) { + // Only enforce 250 ms full suppression after in-call resets, + constexpr int kMuteFramesAfterReset = kNumBlocksPerSecond / 4; + realignment_counter_ = kMuteFramesAfterReset; + } else if (!active_render_seen_ && render_activity) { + // Enforce a tailormade suppression limiting during call startup. + active_render_seen_ = true; + realignment_counter_ = rampup_config_.full_gain_blocks; + } else if (realignment_counter_ > 0) { + if (--realignment_counter_ == 0) { + call_startup_phase_ = false; + } + } + recent_reset_ = false; + + // Do not enforce any gain limit on the suppressor. + if (realignment_counter_ <= 0) { + suppressor_gain_limit_ = 1.f; + return; + } + + // Enforce full suppression. + if (realignment_counter_ > rampup_config_.non_zero_gain_blocks || + (!call_startup_phase_ && realignment_counter_ > 0)) { + suppressor_gain_limit_ = 0.f; + return; + } + + // Start increasing the gain limit. + if (realignment_counter_ == rampup_config_.non_zero_gain_blocks) { + suppressor_gain_limit_ = rampup_config_.first_non_zero_gain; + return; + } + + // Increase the gain limit until it reaches 1.f. + RTC_DCHECK_LT(0.f, suppressor_gain_limit_); + suppressor_gain_limit_ = + std::min(1.f, suppressor_gain_limit_ * gain_rampup_increase_); + RTC_DCHECK_GE(1.f, suppressor_gain_limit_); +} + +} // namespace webrtc diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.h b/modules/audio_processing/aec3/suppression_gain_limiter.h new file mode 100644 index 0000000000..7a3f2285d9 --- /dev/null +++ b/modules/audio_processing/aec3/suppression_gain_limiter.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_ +#define MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_ + +#include "api/array_view.h" +#include "api/audio/echo_canceller3_config.h" +#include "rtc_base/constructormagic.h" + +namespace webrtc { + +// Class for applying a smoothly increasing limit for the suppression gain +// during call startup and after in-call resets. +class SuppressionGainUpperLimiter { + public: + explicit SuppressionGainUpperLimiter(const EchoCanceller3Config& config); + + // Reset the limiting behavior. + void Reset(); + + // Updates the limiting behavior for the current capture bloc. + void Update(bool render_activity); + + // Returns the current suppressor gain limit. + float Limit() const { return suppressor_gain_limit_; } + + private: + const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_; + const float gain_rampup_increase_; + bool call_startup_phase_ = true; + int realignment_counter_ = 0; + bool active_render_seen_ = false; + float suppressor_gain_limit_ = 1.f; + bool recent_reset_ = false; + + RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SuppressionGainUpperLimiter); +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_AEC3_SUPPRESSION_GAIN_LIMITER_H_