AEC3: Using a more conservative frequency response representation of the tails.

Bug: webrtc:13173
Change-Id: Ic469f6226fe079c306cec6f941eeb70d6d9094f3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231682
Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org>
Reviewed-by: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34966}
diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h
index bc7c6f0..0df6450 100644
--- a/api/audio/echo_canceller3_config.h
+++ b/api/audio/echo_canceller3_config.h
@@ -112,6 +112,7 @@
     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 eaf95b3..f6ffd57 100644
--- a/api/audio/echo_canceller3_config_json.cc
+++ b/api/audio/echo_canceller3_config_json.cc
@@ -264,6 +264,8 @@
     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", &section)) {
@@ -569,6 +571,10 @@
   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 a0432e6..dfa932f 100644
--- a/modules/audio_processing/aec3/echo_canceller3.cc
+++ b/modules/audio_processing/aec3/echo_canceller3.cc
@@ -286,6 +286,10 @@
         static_cast<float>(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 f4bd91f..6e7282a 100644
--- a/modules/audio_processing/aec3/reverb_frequency_response.cc
+++ b/modules/audio_processing/aec3/reverb_frequency_response.cc
@@ -49,9 +49,13 @@
 
 }  // 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 @@
     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 b164186..69b16b5 100644
--- a/modules/audio_processing/aec3/reverb_frequency_response.h
+++ b/modules/audio_processing/aec3/reverb_frequency_response.h
@@ -23,7 +23,8 @@
 // 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 @@
               int filter_delay_blocks,
               float linear_filter_quality);
 
+  const bool use_conservative_tail_frequency_response_;
   float average_decay_ = 0.f;
   std::array<float, kFftLengthBy2Plus1> tail_response_;
 };
diff --git a/modules/audio_processing/aec3/reverb_model_estimator.cc b/modules/audio_processing/aec3/reverb_model_estimator.cc
index 7174311..5cd7a78 100644
--- a/modules/audio_processing/aec3/reverb_model_estimator.cc
+++ b/modules/audio_processing/aec3/reverb_model_estimator.cc
@@ -15,7 +15,10 @@
 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<ReverbDecayEstimator>(config);