AEC3: Parametrize the delay estimator to leverage strong echo paths

This CL introduces a new behavior for leveraging early information
about the delay that is acquired before the standard delay estimate
has been established.

To simplify the process of setting the parameters for that, the CL
also surfaces the delay estimator parameters to the config struct.

Bug: webrtc:9720,chromium: 880686
Change-Id: If886813f70cd805bd37752c63913d28398f1c6fe
Reviewed-on: https://webrtc-review.googlesource.com/97860
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org>
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24614}
diff --git a/api/audio/echo_canceller3_config.h b/api/audio/echo_canceller3_config.h
index 4cb9fe6..e7376ed 100644
--- a/api/audio/echo_canceller3_config.h
+++ b/api/audio/echo_canceller3_config.h
@@ -32,6 +32,12 @@
     size_t hysteresis_limit_2_blocks = 1;
     size_t skew_hysteresis_blocks = 3;
     size_t fixed_capture_delay_samples = 0;
+    float delay_estimate_smoothing = 0.7f;
+    float delay_candidate_detection_threshold = 0.2f;
+    struct DelaySelectionThresholds {
+      int initial;
+      int converged;
+    } delay_selection_thresholds = {25, 25};
   } delay;
 
   struct Filter {
diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.cc b/modules/audio_processing/aec3/echo_path_delay_estimator.cc
index 4cae277..638ddc4 100644
--- a/modules/audio_processing/aec3/echo_path_delay_estimator.cc
+++ b/modules/audio_processing/aec3/echo_path_delay_estimator.cc
@@ -47,9 +47,12 @@
           kMatchedFilterAlignmentShiftSizeSubBlocks,
           GetDownSamplingFactor(config) == 8
               ? config.render_levels.poor_excitation_render_limit_ds8
-              : config.render_levels.poor_excitation_render_limit),
+              : config.render_levels.poor_excitation_render_limit,
+          config.delay.delay_estimate_smoothing,
+          config.delay.delay_candidate_detection_threshold),
       matched_filter_lag_aggregator_(data_dumper_,
-                                     matched_filter_.GetMaxFilterLag()) {
+                                     matched_filter_.GetMaxFilterLag(),
+                                     config.delay.delay_selection_thresholds) {
   RTC_DCHECK(data_dumper);
   RTC_DCHECK(down_sampling_factor_ > 0);
 }
diff --git a/modules/audio_processing/aec3/matched_filter.cc b/modules/audio_processing/aec3/matched_filter.cc
index 7486ddf..9573d93 100644
--- a/modules/audio_processing/aec3/matched_filter.cc
+++ b/modules/audio_processing/aec3/matched_filter.cc
@@ -32,6 +32,7 @@
 
 void MatchedFilterCore_NEON(size_t x_start_index,
                             float x2_sum_threshold,
+                            float smoothing,
                             rtc::ArrayView<const float> x,
                             rtc::ArrayView<const float> y,
                             rtc::ArrayView<float> h,
@@ -102,10 +103,10 @@
     // Update the matched filter estimate in an NLMS manner.
     if (x2_sum > x2_sum_threshold && !saturation) {
       RTC_DCHECK_LT(0.f, x2_sum);
-      const float alpha = 0.7f * e / x2_sum;
+      const float alpha = smoothing * e / x2_sum;
       const float32x4_t alpha_128 = vmovq_n_f32(alpha);
 
-      // filter = filter + 0.7 * (y - filter * x) / x * x.
+      // filter = filter + smoothing * (y - filter * x) * x / x * x.
       float* h_p = &h[0];
       x_p = &x[x_start_index];
 
@@ -145,6 +146,7 @@
 
 void MatchedFilterCore_SSE2(size_t x_start_index,
                             float x2_sum_threshold,
+                            float smoothing,
                             rtc::ArrayView<const float> x,
                             rtc::ArrayView<const float> y,
                             rtc::ArrayView<float> h,
@@ -217,10 +219,10 @@
     // Update the matched filter estimate in an NLMS manner.
     if (x2_sum > x2_sum_threshold && !saturation) {
       RTC_DCHECK_LT(0.f, x2_sum);
-      const float alpha = 0.7f * e / x2_sum;
+      const float alpha = smoothing * e / x2_sum;
       const __m128 alpha_128 = _mm_set1_ps(alpha);
 
-      // filter = filter + 0.7 * (y - filter * x) / x * x.
+      // filter = filter + smoothing * (y - filter * x) * x / x * x.
       float* h_p = &h[0];
       x_p = &x[x_start_index];
 
@@ -259,6 +261,7 @@
 
 void MatchedFilterCore(size_t x_start_index,
                        float x2_sum_threshold,
+                       float smoothing,
                        rtc::ArrayView<const float> x,
                        rtc::ArrayView<const float> y,
                        rtc::ArrayView<float> h,
@@ -288,9 +291,9 @@
     // Update the matched filter estimate in an NLMS manner.
     if (x2_sum > x2_sum_threshold && !saturation) {
       RTC_DCHECK_LT(0.f, x2_sum);
-      const float alpha = 0.7f * e / x2_sum;
+      const float alpha = smoothing * e / x2_sum;
 
-      // filter = filter + 0.7 * (y - filter * x) / x * x.
+      // filter = filter + smoothing * (y - filter * x) * x / x * x.
       size_t x_index = x_start_index;
       for (size_t k = 0; k < h.size(); ++k) {
         h[k] += alpha * x[x_index];
@@ -311,7 +314,9 @@
                              size_t window_size_sub_blocks,
                              int num_matched_filters,
                              size_t alignment_shift_sub_blocks,
-                             float excitation_limit)
+                             float excitation_limit,
+                             float smoothing,
+                             float matching_filter_threshold)
     : data_dumper_(data_dumper),
       optimization_(optimization),
       sub_block_size_(sub_block_size),
@@ -321,7 +326,9 @@
           std::vector<float>(window_size_sub_blocks * sub_block_size_, 0.f)),
       lag_estimates_(num_matched_filters),
       filters_offsets_(num_matched_filters, 0),
-      excitation_limit_(excitation_limit) {
+      excitation_limit_(excitation_limit),
+      smoothing_(smoothing),
+      matching_filter_threshold_(matching_filter_threshold) {
   RTC_DCHECK(data_dumper);
   RTC_DCHECK_LT(0, window_size_sub_blocks);
   RTC_DCHECK((kBlockSize % sub_block_size) == 0);
@@ -362,19 +369,19 @@
 #if defined(WEBRTC_ARCH_X86_FAMILY)
       case Aec3Optimization::kSse2:
         aec3::MatchedFilterCore_SSE2(x_start_index, x2_sum_threshold,
-                                     render_buffer.buffer, y, filters_[n],
-                                     &filters_updated, &error_sum);
+                                     smoothing_, render_buffer.buffer, y,
+                                     filters_[n], &filters_updated, &error_sum);
         break;
 #endif
 #if defined(WEBRTC_HAS_NEON)
       case Aec3Optimization::kNeon:
         aec3::MatchedFilterCore_NEON(x_start_index, x2_sum_threshold,
-                                     render_buffer.buffer, y, filters_[n],
-                                     &filters_updated, &error_sum);
+                                     smoothing_, render_buffer.buffer, y,
+                                     filters_[n], &filters_updated, &error_sum);
         break;
 #endif
       default:
-        aec3::MatchedFilterCore(x_start_index, x2_sum_threshold,
+        aec3::MatchedFilterCore(x_start_index, x2_sum_threshold, smoothing_,
                                 render_buffer.buffer, y, filters_[n],
                                 &filters_updated, &error_sum);
     }
@@ -393,11 +400,10 @@
             [](float a, float b) -> bool { return a * a < b * b; }));
 
     // Update the lag estimates for the matched filter.
-    const float kMatchingFilterThreshold = 0.2f;
     lag_estimates_[n] = LagEstimate(
         error_sum_anchor - error_sum,
         (lag_estimate > 2 && lag_estimate < (filters_[n].size() - 10) &&
-         error_sum < kMatchingFilterThreshold * error_sum_anchor),
+         error_sum < matching_filter_threshold_ * error_sum_anchor),
         lag_estimate + alignment_shift, filters_updated);
 
     RTC_DCHECK_GE(10, filters_.size());
diff --git a/modules/audio_processing/aec3/matched_filter.h b/modules/audio_processing/aec3/matched_filter.h
index 1c06b5e..2ef4828 100644
--- a/modules/audio_processing/aec3/matched_filter.h
+++ b/modules/audio_processing/aec3/matched_filter.h
@@ -30,6 +30,7 @@
 // Filter core for the matched filter that is optimized for NEON.
 void MatchedFilterCore_NEON(size_t x_start_index,
                             float x2_sum_threshold,
+                            float smoothing,
                             rtc::ArrayView<const float> x,
                             rtc::ArrayView<const float> y,
                             rtc::ArrayView<float> h,
@@ -43,6 +44,7 @@
 // Filter core for the matched filter that is optimized for SSE2.
 void MatchedFilterCore_SSE2(size_t x_start_index,
                             float x2_sum_threshold,
+                            float smoothing,
                             rtc::ArrayView<const float> x,
                             rtc::ArrayView<const float> y,
                             rtc::ArrayView<float> h,
@@ -54,6 +56,7 @@
 // Filter core for the matched filter.
 void MatchedFilterCore(size_t x_start_index,
                        float x2_sum_threshold,
+                       float smoothing,
                        rtc::ArrayView<const float> x,
                        rtc::ArrayView<const float> y,
                        rtc::ArrayView<float> h,
@@ -87,7 +90,9 @@
                 size_t window_size_sub_blocks,
                 int num_matched_filters,
                 size_t alignment_shift_sub_blocks,
-                float excitation_limit);
+                float excitation_limit,
+                float smoothing,
+                float matching_filter_threshold);
 
   ~MatchedFilter();
 
@@ -122,6 +127,8 @@
   std::vector<LagEstimate> lag_estimates_;
   std::vector<size_t> filters_offsets_;
   const float excitation_limit_;
+  const float smoothing_;
+  const float matching_filter_threshold_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MatchedFilter);
 };
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
index 9cd2eb3..7a03e60 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc
@@ -15,9 +15,13 @@
 
 MatchedFilterLagAggregator::MatchedFilterLagAggregator(
     ApmDataDumper* data_dumper,
-    size_t max_filter_lag)
-    : data_dumper_(data_dumper), histogram_(max_filter_lag + 1, 0) {
+    size_t max_filter_lag,
+    const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds)
+    : data_dumper_(data_dumper),
+      histogram_(max_filter_lag + 1, 0),
+      thresholds_(thresholds) {
   RTC_DCHECK(data_dumper);
+  RTC_DCHECK_LE(thresholds_.initial, thresholds_.converged);
   histogram_data_.fill(0);
 }
 
@@ -67,8 +71,12 @@
         std::distance(histogram_.begin(),
                       std::max_element(histogram_.begin(), histogram_.end()));
 
-    if (histogram_[candidate] > 25) {
-      significant_candidate_found_ = true;
+    significant_candidate_found_ =
+        significant_candidate_found_ ||
+        histogram_[candidate] > thresholds_.converged;
+    if (histogram_[candidate] > thresholds_.converged ||
+        (histogram_[candidate] > thresholds_.initial &&
+         !significant_candidate_found_)) {
       return DelayEstimate(DelayEstimate::Quality::kRefined, candidate);
     }
   }
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
index fddcfbf..c57051a 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h
@@ -14,6 +14,7 @@
 #include <vector>
 
 #include "absl/types/optional.h"
+#include "api/audio/echo_canceller3_config.h"
 #include "modules/audio_processing/aec3/delay_estimate.h"
 #include "modules/audio_processing/aec3/matched_filter.h"
 #include "rtc_base/constructormagic.h"
@@ -26,7 +27,10 @@
 // reliable combined lag estimate.
 class MatchedFilterLagAggregator {
  public:
-  MatchedFilterLagAggregator(ApmDataDumper* data_dumper, size_t max_filter_lag);
+  MatchedFilterLagAggregator(
+      ApmDataDumper* data_dumper,
+      size_t max_filter_lag,
+      const EchoCanceller3Config::Delay::DelaySelectionThresholds& thresholds);
   ~MatchedFilterLagAggregator();
 
   // Resets the aggregator.
@@ -42,6 +46,7 @@
   std::array<int, 250> histogram_data_;
   int histogram_data_index_ = 0;
   bool significant_candidate_found_ = false;
+  const EchoCanceller3Config::Delay::DelaySelectionThresholds thresholds_;
 
   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(MatchedFilterLagAggregator);
 };
diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
index cea5f13..e136c89 100644
--- a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
+++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include "api/array_view.h"
+#include "api/audio/echo_canceller3_config.h"
 #include "modules/audio_processing/aec3/aec3_common.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "test/gtest.h"
@@ -31,8 +32,11 @@
   constexpr size_t kLag1 = 5;
   constexpr size_t kLag2 = 10;
   ApmDataDumper data_dumper(0);
+  EchoCanceller3Config config;
   std::vector<MatchedFilter::LagEstimate> lag_estimates(2);
-  MatchedFilterLagAggregator aggregator(&data_dumper, std::max(kLag1, kLag2));
+  MatchedFilterLagAggregator aggregator(
+      &data_dumper, std::max(kLag1, kLag2),
+      config.delay.delay_selection_thresholds);
   lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag1, true);
   lag_estimates[1] = MatchedFilter::LagEstimate(0.5f, true, kLag2, true);
 
@@ -65,8 +69,10 @@
 TEST(MatchedFilterLagAggregator,
      LagEstimateInvarianceRequiredForAggregatedLag) {
   ApmDataDumper data_dumper(0);
+  EchoCanceller3Config config;
   std::vector<MatchedFilter::LagEstimate> lag_estimates(1);
-  MatchedFilterLagAggregator aggregator(&data_dumper, 100);
+  MatchedFilterLagAggregator aggregator(
+      &data_dumper, 100, config.delay.delay_selection_thresholds);
 
   absl::optional<DelayEstimate> aggregated_lag;
   for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) {
@@ -94,8 +100,10 @@
      DISABLED_LagEstimateUpdatesRequiredForAggregatedLag) {
   constexpr size_t kLag = 5;
   ApmDataDumper data_dumper(0);
+  EchoCanceller3Config config;
   std::vector<MatchedFilter::LagEstimate> lag_estimates(1);
-  MatchedFilterLagAggregator aggregator(&data_dumper, kLag);
+  MatchedFilterLagAggregator aggregator(
+      &data_dumper, kLag, config.delay.delay_selection_thresholds);
   for (size_t k = 0; k < kNumLagsBeforeDetection * 10; ++k) {
     lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag, false);
     absl::optional<DelayEstimate> aggregated_lag =
@@ -112,8 +120,11 @@
   constexpr size_t kLag1 = 5;
   constexpr size_t kLag2 = 10;
   ApmDataDumper data_dumper(0);
+  EchoCanceller3Config config;
   std::vector<MatchedFilter::LagEstimate> lag_estimates(1);
-  MatchedFilterLagAggregator aggregator(&data_dumper, std::max(kLag1, kLag2));
+  MatchedFilterLagAggregator aggregator(
+      &data_dumper, std::max(kLag1, kLag2),
+      config.delay.delay_selection_thresholds);
   absl::optional<DelayEstimate> aggregated_lag;
   for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) {
     lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag1, true);
@@ -134,7 +145,10 @@
 
 // Verifies the check for non-null data dumper.
 TEST(MatchedFilterLagAggregator, NullDataDumper) {
-  EXPECT_DEATH(MatchedFilterLagAggregator(nullptr, 10), "");
+  EchoCanceller3Config config;
+  EXPECT_DEATH(MatchedFilterLagAggregator(
+                   nullptr, 10, config.delay.delay_selection_thresholds),
+               "");
 }
 
 #endif
diff --git a/modules/audio_processing/aec3/matched_filter_unittest.cc b/modules/audio_processing/aec3/matched_filter_unittest.cc
index c13241f..4353003 100644
--- a/modules/audio_processing/aec3/matched_filter_unittest.cc
+++ b/modules/audio_processing/aec3/matched_filter_unittest.cc
@@ -52,6 +52,7 @@
 // counterparts.
 TEST(MatchedFilter, TestNeonOptimizations) {
   Random random_generator(42U);
+  constexpr float kSmoothing = 0.7f;
   for (auto down_sampling_factor : kDownSamplingFactors) {
     const size_t sub_block_size = kBlockSize / down_sampling_factor;
 
@@ -69,10 +70,10 @@
       bool filters_updated_NEON = false;
       float error_sum_NEON = 0.f;
 
-      MatchedFilterCore_NEON(x_index, h.size() * 150.f * 150.f, x, y, h_NEON,
-                             &filters_updated_NEON, &error_sum_NEON);
+      MatchedFilterCore_NEON(x_index, h.size() * 150.f * 150.f, kSmoothing, x,
+                             y, h_NEON, &filters_updated_NEON, &error_sum_NEON);
 
-      MatchedFilterCore(x_index, h.size() * 150.f * 150.f, x, y, h,
+      MatchedFilterCore(x_index, h.size() * 150.f * 150.f, kSmoothing, x, y, h,
                         &filters_updated, &error_sum);
 
       EXPECT_EQ(filters_updated, filters_updated_NEON);
@@ -95,6 +96,7 @@
   bool use_sse2 = (WebRtc_GetCPUInfo(kSSE2) != 0);
   if (use_sse2) {
     Random random_generator(42U);
+    constexpr float kSmoothing = 0.7f;
     for (auto down_sampling_factor : kDownSamplingFactors) {
       const size_t sub_block_size = kBlockSize / down_sampling_factor;
       std::vector<float> x(2000);
@@ -111,11 +113,12 @@
         bool filters_updated_SSE2 = false;
         float error_sum_SSE2 = 0.f;
 
-        MatchedFilterCore_SSE2(x_index, h.size() * 150.f * 150.f, x, y, h_SSE2,
-                               &filters_updated_SSE2, &error_sum_SSE2);
+        MatchedFilterCore_SSE2(x_index, h.size() * 150.f * 150.f, kSmoothing, x,
+                               y, h_SSE2, &filters_updated_SSE2,
+                               &error_sum_SSE2);
 
-        MatchedFilterCore(x_index, h.size() * 150.f * 150.f, x, y, h,
-                          &filters_updated, &error_sum);
+        MatchedFilterCore(x_index, h.size() * 150.f * 150.f, kSmoothing, x, y,
+                          h, &filters_updated, &error_sum);
 
         EXPECT_EQ(filters_updated, filters_updated_SSE2);
         EXPECT_NEAR(error_sum, error_sum_SSE2, error_sum / 100000.f);
@@ -157,7 +160,9 @@
                                              delay_samples);
       MatchedFilter filter(&data_dumper, DetectOptimization(), sub_block_size,
                            kWindowSizeSubBlocks, kNumMatchedFilters,
-                           kAlignmentShiftSubBlocks, 150);
+                           kAlignmentShiftSubBlocks, 150,
+                           config.delay.delay_estimate_smoothing,
+                           config.delay.delay_candidate_detection_threshold);
 
       std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
           RenderDelayBuffer::Create(config, 3));
@@ -259,7 +264,9 @@
         RenderDelayBuffer::Create(config, 3));
     MatchedFilter filter(&data_dumper, DetectOptimization(), sub_block_size,
                          kWindowSizeSubBlocks, kNumMatchedFilters,
-                         kAlignmentShiftSubBlocks, 150);
+                         kAlignmentShiftSubBlocks, 150,
+                         config.delay.delay_estimate_smoothing,
+                         config.delay.delay_candidate_detection_threshold);
 
     // Analyze the correlation between render and capture.
     for (size_t k = 0; k < 100; ++k) {
@@ -292,11 +299,14 @@
     std::array<float, kBlockSize> capture;
     capture.fill(0.f);
     ApmDataDumper data_dumper(0);
+    EchoCanceller3Config config;
     MatchedFilter filter(&data_dumper, DetectOptimization(), sub_block_size,
                          kWindowSizeSubBlocks, kNumMatchedFilters,
-                         kAlignmentShiftSubBlocks, 150);
+                         kAlignmentShiftSubBlocks, 150,
+                         config.delay.delay_estimate_smoothing,
+                         config.delay.delay_candidate_detection_threshold);
     std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
-        RenderDelayBuffer::Create(EchoCanceller3Config(), 3));
+        RenderDelayBuffer::Create(config, 3));
     Decimator capture_decimator(down_sampling_factor);
 
     // Analyze the correlation between render and capture.
@@ -331,12 +341,15 @@
 // number of alignment shifts.
 TEST(MatchedFilter, NumberOfLagEstimates) {
   ApmDataDumper data_dumper(0);
+  EchoCanceller3Config config;
   for (auto down_sampling_factor : kDownSamplingFactors) {
     const size_t sub_block_size = kBlockSize / down_sampling_factor;
     for (size_t num_matched_filters = 0; num_matched_filters < 10;
          ++num_matched_filters) {
       MatchedFilter filter(&data_dumper, DetectOptimization(), sub_block_size,
-                           32, num_matched_filters, 1, 150);
+                           32, num_matched_filters, 1, 150,
+                           config.delay.delay_estimate_smoothing,
+                           config.delay.delay_candidate_detection_threshold);
       EXPECT_EQ(num_matched_filters, filter.GetLagEstimates().size());
     }
   }
@@ -347,13 +360,19 @@
 // Verifies the check for non-zero windows size.
 TEST(MatchedFilter, ZeroWindowSize) {
   ApmDataDumper data_dumper(0);
-  EXPECT_DEATH(
-      MatchedFilter(&data_dumper, DetectOptimization(), 16, 0, 1, 1, 150), "");
+  EchoCanceller3Config config;
+  EXPECT_DEATH(MatchedFilter(&data_dumper, DetectOptimization(), 16, 0, 1, 1,
+                             150, config.delay.delay_estimate_smoothing,
+                             config.delay.delay_candidate_detection_threshold),
+               "");
 }
 
 // Verifies the check for non-null data dumper.
 TEST(MatchedFilter, NullDataDumper) {
-  EXPECT_DEATH(MatchedFilter(nullptr, DetectOptimization(), 16, 1, 1, 1, 150),
+  EchoCanceller3Config config;
+  EXPECT_DEATH(MatchedFilter(nullptr, DetectOptimization(), 16, 1, 1, 1, 150,
+                             config.delay.delay_estimate_smoothing,
+                             config.delay.delay_candidate_detection_threshold),
                "");
 }
 
@@ -361,8 +380,11 @@
 // TODO(peah): Activate the unittest once the required code has been landed.
 TEST(MatchedFilter, DISABLED_BlockSizeMultipleOf4) {
   ApmDataDumper data_dumper(0);
-  EXPECT_DEATH(
-      MatchedFilter(&data_dumper, DetectOptimization(), 15, 1, 1, 1, 150), "");
+  EchoCanceller3Config config;
+  EXPECT_DEATH(MatchedFilter(&data_dumper, DetectOptimization(), 15, 1, 1, 1,
+                             150, config.delay.delay_estimate_smoothing,
+                             config.delay.delay_candidate_detection_threshold),
+               "");
 }
 
 // Verifies the check for that there is an integer number of sub blocks that add
@@ -370,8 +392,11 @@
 // TODO(peah): Activate the unittest once the required code has been landed.
 TEST(MatchedFilter, DISABLED_SubBlockSizeAddsUpToBlockSize) {
   ApmDataDumper data_dumper(0);
-  EXPECT_DEATH(
-      MatchedFilter(&data_dumper, DetectOptimization(), 12, 1, 1, 1, 150), "");
+  EchoCanceller3Config config;
+  EXPECT_DEATH(MatchedFilter(&data_dumper, DetectOptimization(), 12, 1, 1, 1,
+                             150, config.delay.delay_estimate_smoothing,
+                             config.delay.delay_candidate_detection_threshold),
+               "");
 }
 
 #endif
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index e8b8804..9481c98 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -222,6 +222,19 @@
                 &cfg.delay.skew_hysteresis_blocks);
       ReadParam(section, "fixed_capture_delay_samples",
                 &cfg.delay.fixed_capture_delay_samples);
+      ReadParam(section, "delay_estimate_smoothing",
+                &cfg.delay.delay_estimate_smoothing);
+      ReadParam(section, "delay_candidate_detection_threshold",
+                &cfg.delay.delay_candidate_detection_threshold);
+
+      Json::Value subsection;
+      if (rtc::GetValueFromJsonObject(section, "delay_selection_thresholds",
+                                      &subsection)) {
+        ReadParam(subsection, "initial",
+                  &cfg.delay.delay_selection_thresholds.initial);
+        ReadParam(subsection, "converged",
+                  &cfg.delay.delay_selection_thresholds.converged);
+      }
     }
 
     if (rtc::GetValueFromJsonObject(root, "filter", &section)) {