From dd0928751459b7890afeb11060e6a76ce8f3f071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20de=20Vicente=20Pe=C3=B1a?= Date: Fri, 25 May 2018 16:55:11 +0200 Subject: [PATCH] AEC3: Gain limiter: Improving the behavior of the gain limiter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In this work, we change the behavior of the gain limiter so it also looks at the energy on farend around the default delay for deciding the suppression gain that should be applied at the initial portion of the call. Bug: webrtc:9311,chromium:846724 Change-Id: I0b777cedbbd7fd689e72070f72237296ce120d3c Reviewed-on: https://webrtc-review.googlesource.com/78960 Reviewed-by: Per Ã…hgren Commit-Queue: Jesus de Vicente Pena Cr-Commit-Position: refs/heads/master@{#23400} --- api/audio/echo_canceller3_config.cc | 4 + api/audio/echo_canceller3_config.h | 6 +- modules/audio_processing/aec3/aec_state.cc | 2 + modules/audio_processing/aec3/aec_state.h | 5 ++ .../aec3/residual_echo_estimator.cc | 74 +++++++++++++++---- .../aec3/residual_echo_estimator.h | 8 +- .../aec3/suppression_gain_limiter.cc | 4 +- .../aec3/suppression_gain_limiter.h | 3 + modules/audio_processing/aec3/vector_buffer.h | 1 + .../test/audio_processing_simulator.cc | 6 ++ 10 files changed, 92 insertions(+), 21 deletions(-) diff --git a/api/audio/echo_canceller3_config.cc b/api/audio/echo_canceller3_config.cc index c17b0d56c9..9af7f11c57 100644 --- a/api/audio/echo_canceller3_config.cc +++ b/api/audio/echo_canceller3_config.cc @@ -17,4 +17,8 @@ EchoCanceller3Config::EchoCanceller3Config(const EchoCanceller3Config& e) = EchoCanceller3Config::Mask::Mask() = default; EchoCanceller3Config::Mask::Mask(const EchoCanceller3Config::Mask& m) = default; +EchoCanceller3Config::EchoModel::EchoModel() = default; +EchoCanceller3Config::EchoModel::EchoModel( + const EchoCanceller3Config::EchoModel& e) = default; + } // namespace webrtc diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h index 672f2c028d..b82760dc25 100644 --- a/api/audio/echo_canceller3_config.h +++ b/api/audio/echo_canceller3_config.h @@ -128,15 +128,17 @@ struct EchoCanceller3Config { struct EchoRemovalControl { struct GainRampup { + float initial_gain = 0.0f; float first_non_zero_gain = 0.001f; int non_zero_gain_blocks = 187; int full_gain_blocks = 312; } gain_rampup; - bool has_clock_drift = false; } echo_removal_control; struct EchoModel { + EchoModel(); + EchoModel(const EchoModel& e); size_t noise_floor_hold = 50; float min_noise_floor_power = 1638400.f; float stationary_gate_slope = 10.f; @@ -144,6 +146,8 @@ struct EchoCanceller3Config { float noise_gate_slope = 0.3f; size_t render_pre_window_size = 1; size_t render_post_window_size = 1; + size_t render_pre_window_size_init = 10; + size_t render_post_window_size_init = 10; float nonlinear_hold = 1; float nonlinear_release = 0.001f; } echo_model; diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc index b6bbe4490c..1f91777788 100644 --- a/modules/audio_processing/aec3/aec_state.cc +++ b/modules/audio_processing/aec3/aec_state.cc @@ -282,6 +282,8 @@ void AecState::Update( filter_has_had_time_to_converge); data_dumper_->DumpRaw("aec3_recently_converged_filter", recently_converged_filter); + data_dumper_->DumpRaw("aec3_suppresion_gain_limiter_running", + IsSuppressionGainLimitActive()); } void AecState::UpdateReverb(const std::vector& impulse_response) { diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index 39314ff645..4765e84384 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -111,6 +111,11 @@ class AecState { return suppression_gain_limiter_.Limit(); } + // Returns whether the suppression gain limiter is active. + bool IsSuppressionGainLimitActive() const { + return suppression_gain_limiter_.IsActive(); + } + // Returns whether the linear filter should have been able to properly adapt. bool FilterHasHadTimeToConverge() const { return filter_has_had_time_to_converge_; diff --git a/modules/audio_processing/aec3/residual_echo_estimator.cc b/modules/audio_processing/aec3/residual_echo_estimator.cc index da152e9f70..94d12d491a 100644 --- a/modules/audio_processing/aec3/residual_echo_estimator.cc +++ b/modules/audio_processing/aec3/residual_echo_estimator.cc @@ -28,6 +28,45 @@ bool OverrideEstimatedEchoPathGain() { return !field_trial::IsEnabled("WebRTC-Aec3OverrideEchoPathGainKillSwitch"); } +// Computes the indexes that will be used for computing spectral power over +// the blocks surrounding the delay. +void GetRenderIndexesToAnalyze( + const VectorBuffer& spectrum_buffer, + const EchoCanceller3Config::EchoModel& echo_model, + int filter_delay_blocks, + bool gain_limiter_running, + int headroom, + int* idx_start, + int* idx_stop) { + RTC_DCHECK(idx_start); + RTC_DCHECK(idx_stop); + if (gain_limiter_running) { + if (static_cast(headroom) > + echo_model.render_post_window_size_init) { + *idx_start = spectrum_buffer.OffsetIndex( + spectrum_buffer.read, + -static_cast(echo_model.render_post_window_size_init)); + } else { + *idx_start = spectrum_buffer.IncIndex(spectrum_buffer.write); + } + + *idx_stop = spectrum_buffer.OffsetIndex( + spectrum_buffer.read, echo_model.render_pre_window_size_init); + } else { + size_t window_start; + size_t window_end; + window_start = + std::max(0, filter_delay_blocks - + static_cast(echo_model.render_pre_window_size)); + window_end = filter_delay_blocks + + static_cast(echo_model.render_post_window_size); + *idx_start = + spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_start); + *idx_stop = + spectrum_buffer.OffsetIndex(spectrum_buffer.read, window_end + 1); + } +} + } // namespace ResidualEchoEstimator::ResidualEchoEstimator(const EchoCanceller3Config& config) @@ -61,14 +100,9 @@ void ResidualEchoEstimator::Estimate( // Estimate the echo generating signal power. std::array X2; - // Computes the spectral power over the blocks surrounding the delay. - size_t window_start = std::max( - 0, aec_state.FilterDelayBlocks() - - static_cast(config_.echo_model.render_pre_window_size)); - size_t window_end = - aec_state.FilterDelayBlocks() + - static_cast(config_.echo_model.render_post_window_size); - EchoGeneratingPower(render_buffer, window_start, window_end, + EchoGeneratingPower(render_buffer.GetSpectrumBuffer(), config_.echo_model, + render_buffer.Headroom(), aec_state.FilterDelayBlocks(), + aec_state.IsSuppressionGainLimitActive(), !aec_state.UseStationaryProperties(), &X2); // Subtract the stationary noise power to avoid stationary noise causing @@ -81,8 +115,9 @@ void ResidualEchoEstimator::Estimate( float echo_path_gain; if (override_estimated_echo_path_gain_) { - echo_path_gain = - aec_state.TransparentMode() && soft_transparent_mode_ ? 0.01f : 1.f; + echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_ + ? 0.01f + : config_.ep_strength.lf; } else { echo_path_gain = aec_state.TransparentMode() && soft_transparent_mode_ ? 0.01f @@ -208,14 +243,23 @@ void ResidualEchoEstimator::AddEchoReverb( } void ResidualEchoEstimator::EchoGeneratingPower( - const RenderBuffer& render_buffer, - size_t min_delay, - size_t max_delay, + const VectorBuffer& spectrum_buffer, + const EchoCanceller3Config::EchoModel& echo_model, + int headroom_spectrum_buffer, + int filter_delay_blocks, + bool gain_limiter_running, bool apply_noise_gating, std::array* X2) const { + int idx_stop, idx_start; + + RTC_DCHECK(X2); + GetRenderIndexesToAnalyze(spectrum_buffer, config_.echo_model, + filter_delay_blocks, gain_limiter_running, + headroom_spectrum_buffer, &idx_start, &idx_stop); + X2->fill(0.f); - for (size_t k = min_delay; k <= max_delay; ++k) { - std::transform(X2->begin(), X2->end(), render_buffer.Spectrum(k).begin(), + for (int k = idx_start; k != idx_stop; k = spectrum_buffer.IncIndex(k)) { + std::transform(X2->begin(), X2->end(), spectrum_buffer.buffer[k].begin(), X2->begin(), [](float a, float b) { return std::max(a, b); }); } diff --git a/modules/audio_processing/aec3/residual_echo_estimator.h b/modules/audio_processing/aec3/residual_echo_estimator.h index 5c8ba55368..79699fcfc1 100644 --- a/modules/audio_processing/aec3/residual_echo_estimator.h +++ b/modules/audio_processing/aec3/residual_echo_estimator.h @@ -61,9 +61,11 @@ class ResidualEchoEstimator { // Estimates the echo generating signal power as gated maximal power over a // time window. - void EchoGeneratingPower(const RenderBuffer& render_buffer, - size_t min_delay, - size_t max_delay, + void EchoGeneratingPower(const VectorBuffer& spectrum_buffer, + const EchoCanceller3Config::EchoModel& echo_model, + int headroom_spectrum_buffer, + int filter_delay_blocks, + bool gain_limiter_running, bool apply_noise_gating, std::array* X2) const; diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.cc b/modules/audio_processing/aec3/suppression_gain_limiter.cc index 52218eb1a6..e3d7a660bf 100644 --- a/modules/audio_processing/aec3/suppression_gain_limiter.cc +++ b/modules/audio_processing/aec3/suppression_gain_limiter.cc @@ -64,7 +64,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity, recent_reset_ = false; // Do not enforce any gain limit on the suppressor. - if (realignment_counter_ <= 0) { + if (!IsActive()) { suppressor_gain_limit_ = 1.f; return; } @@ -72,7 +72,7 @@ void SuppressionGainUpperLimiter::Update(bool render_activity, // Enforce full suppression. if (realignment_counter_ > rampup_config_.non_zero_gain_blocks || (!call_startup_phase_ && realignment_counter_ > 0)) { - suppressor_gain_limit_ = 0.f; + suppressor_gain_limit_ = rampup_config_.initial_gain; return; } diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.h b/modules/audio_processing/aec3/suppression_gain_limiter.h index e02f491d06..717868ac0a 100644 --- a/modules/audio_processing/aec3/suppression_gain_limiter.h +++ b/modules/audio_processing/aec3/suppression_gain_limiter.h @@ -32,6 +32,9 @@ class SuppressionGainUpperLimiter { // Returns the current suppressor gain limit. float Limit() const { return suppressor_gain_limit_; } + // Return whether the suppressor gain limit is active. + bool IsActive() const { return (realignment_counter_ > 0); } + private: const EchoCanceller3Config::EchoRemovalControl::GainRampup rampup_config_; const float gain_rampup_increase_; diff --git a/modules/audio_processing/aec3/vector_buffer.h b/modules/audio_processing/aec3/vector_buffer.h index a7f9932545..c7d4f68b27 100644 --- a/modules/audio_processing/aec3/vector_buffer.h +++ b/modules/audio_processing/aec3/vector_buffer.h @@ -36,6 +36,7 @@ struct VectorBuffer { int OffsetIndex(int index, int offset) const { RTC_DCHECK_GE(size, offset); RTC_DCHECK_EQ(buffer.size(), static_cast(size)); + RTC_DCHECK_GE(size + index + offset, 0); return (size + index + offset) % size; } diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc index c93d0e7e1f..7e191948e4 100644 --- a/modules/audio_processing/test/audio_processing_simulator.cc +++ b/modules/audio_processing/test/audio_processing_simulator.cc @@ -255,6 +255,8 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) { if (rtc::GetValueFromJsonObject(root, "echo_removal_control", §ion)) { Json::Value subsection; if (rtc::GetValueFromJsonObject(section, "gain_rampup", &subsection)) { + ReadParam(subsection, "initial_gain", + &cfg.echo_removal_control.gain_rampup.initial_gain); ReadParam(subsection, "first_non_zero_gain", &cfg.echo_removal_control.gain_rampup.first_non_zero_gain); ReadParam(subsection, "non_zero_gain_blocks", @@ -279,6 +281,10 @@ EchoCanceller3Config ParseAec3Parameters(const std::string& filename) { &cfg.echo_model.render_pre_window_size); ReadParam(section, "render_post_window_size", &cfg.echo_model.render_post_window_size); + ReadParam(section, "render_pre_window_size_init", + &cfg.echo_model.render_pre_window_size_init); + ReadParam(section, "render_post_window_size_init", + &cfg.echo_model.render_post_window_size_init); ReadParam(section, "nonlinear_hold", &cfg.echo_model.nonlinear_hold); ReadParam(section, "nonlinear_release", &cfg.echo_model.nonlinear_release); }