Further tuning for AEC3 for initial echo suppression
and handling of echo path changes.

This CL add tuning for the AEC3 that
1) Improves the handling of the initial echo suppression
before the linear filter is reliable.
2) Improves the handling of echo path changes.

There are also minor bugfixes included.

BUG=webrtc:6018

Review-Url: https://codereview.webrtc.org/2717353002
Cr-Commit-Position: refs/heads/master@{#16873}
diff --git a/webrtc/modules/audio_processing/aec3/aec_state.cc b/webrtc/modules/audio_processing/aec3/aec_state.cc
index c18fd6d..e43cfc4 100644
--- a/webrtc/modules/audio_processing/aec3/aec_state.cc
+++ b/webrtc/modules/audio_processing/aec3/aec_state.cc
@@ -81,7 +81,7 @@
 constexpr int kActiveRenderCounterInitial = 50;
 constexpr int kActiveRenderCounterMax = 200;
 constexpr int kEchoPathChangeCounterInitial = 50;
-constexpr int kEchoPathChangeCounterMax = 200;
+constexpr int kEchoPathChangeCounterMax = 3 * 250;
 
 }  // namespace
 
@@ -120,6 +120,9 @@
 
   const float x_energy = std::inner_product(x.begin(), x.end(), x.begin(), 0.f);
 
+  active_render_blocks_ =
+      echo_path_variability.AudioPathChanged() ? 0 : active_render_blocks_ + 1;
+
   echo_path_change_counter_ = echo_path_variability.AudioPathChanged()
                                   ? kEchoPathChangeCounterMax
                                   : echo_path_change_counter_ - 1;
diff --git a/webrtc/modules/audio_processing/aec3/aec_state.h b/webrtc/modules/audio_processing/aec3/aec_state.h
index e3502b4..56fee2c 100644
--- a/webrtc/modules/audio_processing/aec3/aec_state.h
+++ b/webrtc/modules/audio_processing/aec3/aec_state.h
@@ -47,6 +47,10 @@
   // Returns whether the render signal is currently active.
   bool ActiveRender() const { return active_render_counter_ > 0; }
 
+  // Returns whether the number of active render blocks since an echo path
+  // change.
+  size_t ActiveRenderBlocks() const { return active_render_blocks_; }
+
   // Returns the ERLE.
   const std::array<float, kFftLengthBy2Plus1>& Erle() const {
     return erle_estimator_.Erle();
@@ -108,6 +112,7 @@
   ErleEstimator erle_estimator_;
   int echo_path_change_counter_;
   int active_render_counter_;
+  size_t active_render_blocks_ = 0;
   bool usable_linear_estimate_ = false;
   bool echo_leakage_detected_ = false;
   bool model_based_aec_feasible_ = false;
diff --git a/webrtc/modules/audio_processing/aec3/echo_canceller3.cc b/webrtc/modules/audio_processing/aec3/echo_canceller3.cc
index 60efced..ed12a47 100644
--- a/webrtc/modules/audio_processing/aec3/echo_canceller3.cc
+++ b/webrtc/modules/audio_processing/aec3/echo_canceller3.cc
@@ -260,7 +260,7 @@
 void EchoCanceller3::AnalyzeCapture(AudioBuffer* capture) {
   RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_);
   RTC_DCHECK(capture);
-  data_dumper_->DumpWav("aec3_capture_analyze_input", frame_length_,
+  data_dumper_->DumpWav("aec3_capture_analyze_input", capture->num_frames(),
                         capture->channels_f()[0], sample_rate_hz_, 1);
 
   saturated_microphone_signal_ = false;
diff --git a/webrtc/modules/audio_processing/aec3/echo_remover.cc b/webrtc/modules/audio_processing/aec3/echo_remover.cc
index 47ff4c2..2d63286 100644
--- a/webrtc/modules/audio_processing/aec3/echo_remover.cc
+++ b/webrtc/modules/audio_processing/aec3/echo_remover.cc
@@ -143,6 +143,7 @@
   if (echo_path_variability.AudioPathChanged()) {
     subtractor_.HandleEchoPathChange(echo_path_variability);
     power_echo_model_.HandleEchoPathChange(echo_path_variability);
+    residual_echo_estimator_.HandleEchoPathChange(echo_path_variability);
   }
 
   std::array<float, kFftLengthBy2Plus1> Y2;
diff --git a/webrtc/modules/audio_processing/aec3/power_echo_model.cc b/webrtc/modules/audio_processing/aec3/power_echo_model.cc
index 8ad5486..9bdc971 100644
--- a/webrtc/modules/audio_processing/aec3/power_echo_model.cc
+++ b/webrtc/modules/audio_processing/aec3/power_echo_model.cc
@@ -28,7 +28,7 @@
   }
 }
 
-constexpr float kHInitial = 10.f;
+constexpr float kHInitial = 100.f;
 constexpr int kUpdateCounterInitial = 300;
 
 }  // namespace
diff --git a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc
index 38d5beb..18a07b2 100644
--- a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc
+++ b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.cc
@@ -20,15 +20,16 @@
 
 constexpr float kSaturationLeakageFactor = 10.f;
 constexpr size_t kSaturationLeakageBlocks = 10;
+constexpr size_t kEchoPathChangeConvergenceBlocks = 3 * 250;
 
 // Estimates the residual echo power when there is no detection correlation
 // between the render and capture signals.
 void InfiniteErlPowerEstimate(
-    size_t active_render_counter,
+    size_t active_render_blocks,
     size_t blocks_since_last_saturation,
     const std::array<float, kFftLengthBy2Plus1>& S2_fallback,
     std::array<float, kFftLengthBy2Plus1>* R2) {
-  if (active_render_counter > 5 * 250) {
+  if (active_render_blocks > 5 * 250) {
     // After an amount of active render samples for which an echo should have
     // been detected in the capture signal if the ERL was not infinite, set the
     // residual echo to 0.
@@ -62,6 +63,7 @@
     size_t external_delay,
     const FftBuffer& X_buffer,
     size_t blocks_since_last_saturation,
+    size_t active_render_blocks,
     const std::array<bool, kFftLengthBy2Plus1>& bands_with_reliable_filter,
     const std::array<float, kFftLengthBy2Plus1>& echo_path_gain,
     const std::array<float, kFftLengthBy2Plus1>& S2_fallback,
@@ -71,10 +73,17 @@
   // Base the residual echo power on gain of the linear echo path estimate if
   // that is reliable, otherwise use the fallback echo path estimate. Add a
   // leakage factor when there is saturation.
-  for (size_t k = 0; k < R2->size(); ++k) {
-    (*R2)[k] = bands_with_reliable_filter[k] ? echo_path_gain[k] * X2[k]
-                                             : S2_fallback[k];
+  if (active_render_blocks > kEchoPathChangeConvergenceBlocks) {
+    for (size_t k = 0; k < R2->size(); ++k) {
+      (*R2)[k] = bands_with_reliable_filter[k] ? echo_path_gain[k] * X2[k]
+                                               : S2_fallback[k];
+    }
+  } else {
+    for (size_t k = 0; k < R2->size(); ++k) {
+      (*R2)[k] = S2_fallback[k];
+    }
   }
+
   if (blocks_since_last_saturation < kSaturationLeakageBlocks) {
     std::for_each(R2->begin(), R2->end(),
                   [](float& a) { a *= kSaturationLeakageFactor; });
@@ -145,7 +154,7 @@
 }  // namespace
 
 ResidualEchoEstimator::ResidualEchoEstimator() {
-  echo_path_gain_.fill(0.f);
+  echo_path_gain_.fill(100.f);
 }
 
 ResidualEchoEstimator::~ResidualEchoEstimator() = default;
@@ -169,6 +178,10 @@
   if (linear_filter_based_delay) {
     std::copy(H2[*linear_filter_based_delay].begin(),
               H2[*linear_filter_based_delay].end(), echo_path_gain_.begin());
+    constexpr float kEchoPathGainHeadroom = 10.f;
+    std::for_each(
+        echo_path_gain_.begin(), echo_path_gain_.end(),
+        [kEchoPathGainHeadroom](float& a) { a *= kEchoPathGainHeadroom; });
   }
 
   // Counts the blocks since saturation.
@@ -178,11 +191,6 @@
     ++blocks_since_last_saturation_;
   }
 
-  // Counts the number of active render blocks that are in a row.
-  if (aec_state.ActiveRender()) {
-    ++active_render_counter_;
-  }
-
   const auto& bands_with_reliable_filter = aec_state.BandsWithReliableFilter();
 
   if (aec_state.UsableLinearEstimate()) {
@@ -200,16 +208,25 @@
     RTC_DCHECK(aec_state.ExternalDelay());
     GainBasedPowerEstimate(
         *aec_state.ExternalDelay(), X_buffer, blocks_since_last_saturation_,
-        bands_with_reliable_filter, echo_path_gain_, S2_fallback, R2);
+        aec_state.ActiveRenderBlocks(), bands_with_reliable_filter,
+        echo_path_gain_, S2_fallback, R2);
   } else if (aec_state.EchoLeakageDetected()) {
     // Residual echo power when an external residual echo detection algorithm
     // has deemed the echo canceller to leak echoes.
     HalfDuplexPowerEstimate(aec_state.ActiveRender(), Y2, R2);
   } else {
     // Residual echo power when none of the other cases are fulfilled.
-    InfiniteErlPowerEstimate(active_render_counter_,
+    InfiniteErlPowerEstimate(aec_state.ActiveRenderBlocks(),
                              blocks_since_last_saturation_, S2_fallback, R2);
   }
 }
 
+void ResidualEchoEstimator::HandleEchoPathChange(
+    const EchoPathVariability& echo_path_variability) {
+  if (echo_path_variability.AudioPathChanged()) {
+    blocks_since_last_saturation_ = 0;
+    echo_path_gain_.fill(100.f);
+  }
+}
+
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h
index 6c59f43..a4f85c4 100644
--- a/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h
+++ b/webrtc/modules/audio_processing/aec3/residual_echo_estimator.h
@@ -39,9 +39,10 @@
                 const std::array<float, kFftLengthBy2Plus1>& Y2,
                 std::array<float, kFftLengthBy2Plus1>* R2);
 
+  void HandleEchoPathChange(const EchoPathVariability& echo_path_variability);
+
  private:
   std::array<float, kFftLengthBy2Plus1> echo_path_gain_;
-  size_t active_render_counter_ = 0;
   size_t blocks_since_last_saturation_ = 1000;
 
   RTC_DISALLOW_COPY_AND_ASSIGN(ResidualEchoEstimator);