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); }