AEC3: Gain limiter: Improving the behavior of the gain limiter.

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 <peah@webrtc.org>
Commit-Queue: Jesus de Vicente Pena <devicentepena@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23400}
diff --git a/modules/audio_processing/aec3/aec_state.cc b/modules/audio_processing/aec3/aec_state.cc
index b6bbe44..1f91777 100644
--- a/modules/audio_processing/aec3/aec_state.cc
+++ b/modules/audio_processing/aec3/aec_state.cc
@@ -282,6 +282,8 @@
                         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<float>& impulse_response) {
diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h
index 39314ff..4765e84 100644
--- a/modules/audio_processing/aec3/aec_state.h
+++ b/modules/audio_processing/aec3/aec_state.h
@@ -111,6 +111,11 @@
     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 da152e9..94d12d4 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.cc
+++ b/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -28,6 +28,45 @@
   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<size_t>(headroom) >
+        echo_model.render_post_window_size_init) {
+      *idx_start = spectrum_buffer.OffsetIndex(
+          spectrum_buffer.read,
+          -static_cast<int>(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<int>(echo_model.render_pre_window_size));
+    window_end = filter_delay_blocks +
+                 static_cast<int>(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 @@
     // Estimate the echo generating signal power.
     std::array<float, kFftLengthBy2Plus1> X2;
 
-    // Computes the spectral power over the blocks surrounding the delay.
-    size_t window_start = std::max(
-        0, aec_state.FilterDelayBlocks() -
-               static_cast<int>(config_.echo_model.render_pre_window_size));
-    size_t window_end =
-        aec_state.FilterDelayBlocks() +
-        static_cast<int>(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 @@
 
     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::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<float, kFftLengthBy2Plus1>* 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 5c8ba55..79699fc 100644
--- a/modules/audio_processing/aec3/residual_echo_estimator.h
+++ b/modules/audio_processing/aec3/residual_echo_estimator.h
@@ -61,9 +61,11 @@
 
   // 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<float, kFftLengthBy2Plus1>* X2) const;
 
diff --git a/modules/audio_processing/aec3/suppression_gain_limiter.cc b/modules/audio_processing/aec3/suppression_gain_limiter.cc
index 52218eb..e3d7a66 100644
--- a/modules/audio_processing/aec3/suppression_gain_limiter.cc
+++ b/modules/audio_processing/aec3/suppression_gain_limiter.cc
@@ -64,7 +64,7 @@
   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 @@
   // 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 e02f491..717868a 100644
--- a/modules/audio_processing/aec3/suppression_gain_limiter.h
+++ b/modules/audio_processing/aec3/suppression_gain_limiter.h
@@ -32,6 +32,9 @@
   // 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 a7f9932..c7d4f68 100644
--- a/modules/audio_processing/aec3/vector_buffer.h
+++ b/modules/audio_processing/aec3/vector_buffer.h
@@ -36,6 +36,7 @@
   int OffsetIndex(int index, int offset) const {
     RTC_DCHECK_GE(size, offset);
     RTC_DCHECK_EQ(buffer.size(), static_cast<size_t>(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 c93d0e7..7e19194 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -255,6 +255,8 @@
   if (rtc::GetValueFromJsonObject(root, "echo_removal_control", &section)) {
     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 @@
               &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);
   }