Make AEC3 recover more quickly for lost capture data

This CL ensures that AEC3 recovers more quickly when capture data is
lost in such a manner that the echo path, as seen by AEC3, becomes
noncausal due to the AEC3 buffer misalignment caused by the data loss.

The CL adds the assumption of a minimum echo path delay of 5 blocks
and makes the hysteresis in the delay selection one-sided.

BUG=chromium:757796, webrtc:8131

Review-Url: https://codereview.webrtc.org/2998223002
Cr-Original-Commit-Position: refs/heads/master@{#19454}
Cr-Mirrored-From: https://chromium.googlesource.com/external/webrtc
Cr-Mirrored-Commit: 96b951c593a2665cc8688d60343dc225f62f4e99
diff --git a/modules/audio_processing/aec3/aec3_common.h b/modules/audio_processing/aec3/aec3_common.h
index b781183..bf62c0e 100644
--- a/modules/audio_processing/aec3/aec3_common.h
+++ b/modules/audio_processing/aec3/aec3_common.h
@@ -63,6 +63,7 @@
 constexpr size_t kRenderDelayBufferSize =
     (3 * kDownsampledRenderBufferSize) / (4 * kSubBlockSize);
 
+constexpr size_t kMinEchoPathDelayBlocks = 5;
 constexpr size_t kMaxApiCallsJitterBlocks = 30;
 constexpr size_t kRenderTransferQueueSize = kMaxApiCallsJitterBlocks / 2;
 static_assert(2 * kRenderTransferQueueSize >= kMaxApiCallsJitterBlocks,
diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc
index 3a32f3c..52bc4ef 100644
--- a/modules/audio_processing/aec3/block_processor.cc
+++ b/modules/audio_processing/aec3/block_processor.cc
@@ -112,20 +112,27 @@
   const size_t old_delay = render_buffer_->Delay();
   const size_t new_delay = delay_controller_->GetDelay(
       render_buffer_->GetDownsampledRenderBuffer(), (*capture_block)[0]);
-  render_buffer_->SetDelay(new_delay);
-  const size_t achieved_delay = render_buffer_->Delay();
 
-  // Inform the delay controller of the actually set delay to allow it to
-  // properly react to a non-feasible delay.
-  delay_controller_->SetDelay(achieved_delay);
+  bool delay_change;
+  if (new_delay >= kMinEchoPathDelayBlocks) {
+    render_buffer_->SetDelay(new_delay);
+    const size_t achieved_delay = render_buffer_->Delay();
+    delay_change = old_delay != achieved_delay || old_delay != new_delay ||
+                   render_buffer_overrun_occurred_;
+
+    // Inform the delay controller of the actually set delay to allow it to
+    // properly react to a non-feasible delay.
+    delay_controller_->SetDelay(achieved_delay);
+  } else {
+    delay_controller_->Reset();
+    render_buffer_->Reset();
+    delay_change = true;
+  }
 
   // Remove the echo from the capture signal.
   echo_remover_->ProcessCapture(
       delay_controller_->AlignmentHeadroomSamples(),
-      EchoPathVariability(echo_path_gain_change,
-                          old_delay != achieved_delay ||
-                              old_delay != new_delay ||
-                              render_buffer_overrun_occurred_),
+      EchoPathVariability(echo_path_gain_change, delay_change),
       capture_signal_saturation, render_buffer_->GetRenderBuffer(),
       capture_block);
 
diff --git a/modules/audio_processing/aec3/render_delay_controller.cc b/modules/audio_processing/aec3/render_delay_controller.cc
index 06074e2..a88540e 100644
--- a/modules/audio_processing/aec3/render_delay_controller.cc
+++ b/modules/audio_processing/aec3/render_delay_controller.cc
@@ -59,7 +59,7 @@
   size_t new_delay = std::max(echo_path_delay_blocks - kDelayHeadroomBlocks, 0);
 
   // Add hysteresis.
-  if (new_delay == current_delay + 1 || new_delay + 1 == current_delay) {
+  if (new_delay == current_delay + 1) {
     new_delay = current_delay;
   }
 
@@ -78,7 +78,7 @@
 RenderDelayControllerImpl::~RenderDelayControllerImpl() = default;
 
 void RenderDelayControllerImpl::Reset() {
-  delay_ = 0;
+  delay_ = kMinEchoPathDelayBlocks;
   blocks_since_last_delay_estimate_ = 300000;
   echo_path_delay_samples_ = 0;
   align_call_counter_ = 0;