diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h index bc7c6f0019..0df6450872 100644 --- a/api/audio/echo_canceller3_config.h +++ b/api/audio/echo_canceller3_config.h @@ -112,6 +112,7 @@ struct RTC_EXPORT EchoCanceller3Config { bool echo_can_saturate = true; bool bounded_erl = false; bool erle_onset_compensation_in_dominant_nearend = false; + bool use_conservative_tail_frequency_response = false; } ep_strength; struct EchoAudibility { diff --git a/api/audio/echo_canceller3_config_json.cc b/api/audio/echo_canceller3_config_json.cc index eaf95b3071..f6ffd575ea 100644 --- a/api/audio/echo_canceller3_config_json.cc +++ b/api/audio/echo_canceller3_config_json.cc @@ -264,6 +264,8 @@ void Aec3ConfigFromJsonString(absl::string_view json_string, ReadParam(section, "bounded_erl", &cfg.ep_strength.bounded_erl); ReadParam(section, "erle_onset_compensation_in_dominant_nearend", &cfg.ep_strength.erle_onset_compensation_in_dominant_nearend); + ReadParam(section, "use_conservative_tail_frequency_response", + &cfg.ep_strength.use_conservative_tail_frequency_response); } if (rtc::GetValueFromJsonObject(aec3_root, "echo_audibility", §ion)) { @@ -568,6 +570,10 @@ std::string Aec3ConfigToJsonString(const EchoCanceller3Config& config) { << (config.ep_strength.bounded_erl ? "true" : "false") << ","; ost << "\"erle_onset_compensation_in_dominant_nearend\": " << (config.ep_strength.erle_onset_compensation_in_dominant_nearend + ? "true" + : "false") << ","; + ost << "\"use_conservative_tail_frequency_response\": " + << (config.ep_strength.use_conservative_tail_frequency_response ? "true" : "false"); ost << "},"; diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc index a0432e624c..dfa932f49c 100644 --- a/modules/audio_processing/aec3/echo_canceller3.cc +++ b/modules/audio_processing/aec3/echo_canceller3.cc @@ -286,6 +286,10 @@ EchoCanceller3Config AdjustConfig(const EchoCanceller3Config& config) { static_cast(nearend_reverb_nearend_len.Get()); } + if (field_trial::IsEnabled("WebRTC-Aec3ConservativeTailFreqResponse")) { + adjusted_cfg.ep_strength.use_conservative_tail_frequency_response = true; + } + if (field_trial::IsEnabled("WebRTC-Aec3ShortHeadroomKillSwitch")) { // Two blocks headroom. adjusted_cfg.delay.delay_headroom_samples = kBlockSize * 2; diff --git a/modules/audio_processing/aec3/reverb_frequency_response.cc b/modules/audio_processing/aec3/reverb_frequency_response.cc index f4bd91fd48..6e7282a1fc 100644 --- a/modules/audio_processing/aec3/reverb_frequency_response.cc +++ b/modules/audio_processing/aec3/reverb_frequency_response.cc @@ -49,9 +49,13 @@ float AverageDecayWithinFilter( } // namespace -ReverbFrequencyResponse::ReverbFrequencyResponse() { - tail_response_.fill(0.f); +ReverbFrequencyResponse::ReverbFrequencyResponse( + bool use_conservative_tail_frequency_response) + : use_conservative_tail_frequency_response_( + use_conservative_tail_frequency_response) { + tail_response_.fill(0.0f); } + ReverbFrequencyResponse::~ReverbFrequencyResponse() = default; void ReverbFrequencyResponse::Update( @@ -88,6 +92,12 @@ void ReverbFrequencyResponse::Update( tail_response_[k] = freq_resp_direct_path[k] * average_decay_; } + if (use_conservative_tail_frequency_response_) { + for (size_t k = 0; k < kFftLengthBy2Plus1; ++k) { + tail_response_[k] = std::max(freq_resp_tail[k], tail_response_[k]); + } + } + for (size_t k = 1; k < kFftLengthBy2; ++k) { const float avg_neighbour = 0.5f * (tail_response_[k - 1] + tail_response_[k + 1]); diff --git a/modules/audio_processing/aec3/reverb_frequency_response.h b/modules/audio_processing/aec3/reverb_frequency_response.h index b16418628b..69b16b54d0 100644 --- a/modules/audio_processing/aec3/reverb_frequency_response.h +++ b/modules/audio_processing/aec3/reverb_frequency_response.h @@ -23,7 +23,8 @@ namespace webrtc { // Class for updating the frequency response for the reverb. class ReverbFrequencyResponse { public: - ReverbFrequencyResponse(); + explicit ReverbFrequencyResponse( + bool use_conservative_tail_frequency_response); ~ReverbFrequencyResponse(); // Updates the frequency response estimate of the reverb. @@ -44,6 +45,7 @@ class ReverbFrequencyResponse { int filter_delay_blocks, float linear_filter_quality); + const bool use_conservative_tail_frequency_response_; float average_decay_ = 0.f; std::array tail_response_; }; diff --git a/modules/audio_processing/aec3/reverb_model_estimator.cc b/modules/audio_processing/aec3/reverb_model_estimator.cc index 717431103f..5cd7a7870d 100644 --- a/modules/audio_processing/aec3/reverb_model_estimator.cc +++ b/modules/audio_processing/aec3/reverb_model_estimator.cc @@ -15,7 +15,10 @@ namespace webrtc { ReverbModelEstimator::ReverbModelEstimator(const EchoCanceller3Config& config, size_t num_capture_channels) : reverb_decay_estimators_(num_capture_channels), - reverb_frequency_responses_(num_capture_channels) { + reverb_frequency_responses_( + num_capture_channels, + ReverbFrequencyResponse( + config.ep_strength.use_conservative_tail_frequency_response)) { for (size_t ch = 0; ch < reverb_decay_estimators_.size(); ++ch) { reverb_decay_estimators_[ch] = std::make_unique(config);