1 /*
2  *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_processing/aec3/adaptive_fir_filter.h"
12 
13 // Defines WEBRTC_ARCH_X86_FAMILY, used below.
14 #include <math.h>
15 
16 #include <algorithm>
17 #include <numeric>
18 #include <string>
19 
20 #include "rtc_base/system/arch.h"
21 #if defined(WEBRTC_ARCH_X86_FAMILY)
22 #include <emmintrin.h>
23 #endif
24 
25 #include "modules/audio_processing/aec3/adaptive_fir_filter_erl.h"
26 #include "modules/audio_processing/aec3/aec3_fft.h"
27 #include "modules/audio_processing/aec3/aec_state.h"
28 #include "modules/audio_processing/aec3/coarse_filter_update_gain.h"
29 #include "modules/audio_processing/aec3/render_delay_buffer.h"
30 #include "modules/audio_processing/aec3/render_signal_analyzer.h"
31 #include "modules/audio_processing/logging/apm_data_dumper.h"
32 #include "modules/audio_processing/test/echo_canceller_test_tools.h"
33 #include "modules/audio_processing/utility/cascaded_biquad_filter.h"
34 #include "rtc_base/arraysize.h"
35 #include "rtc_base/numerics/safe_minmax.h"
36 #include "rtc_base/random.h"
37 #include "rtc_base/strings/string_builder.h"
38 #include "system_wrappers/include/cpu_features_wrapper.h"
39 #include "test/gtest.h"
40 
41 namespace webrtc {
42 namespace aec3 {
43 namespace {
44 
ProduceDebugText(size_t num_render_channels,size_t delay)45 std::string ProduceDebugText(size_t num_render_channels, size_t delay) {
46   rtc::StringBuilder ss;
47   ss << "delay: " << delay << ", ";
48   ss << "num_render_channels:" << num_render_channels;
49   return ss.Release();
50 }
51 
52 }  // namespace
53 
54 class AdaptiveFirFilterOneTwoFourEightRenderChannels
55     : public ::testing::Test,
56       public ::testing::WithParamInterface<size_t> {};
57 
58 INSTANTIATE_TEST_SUITE_P(MultiChannel,
59                          AdaptiveFirFilterOneTwoFourEightRenderChannels,
60                          ::testing::Values(1, 2, 4, 8));
61 
62 #if defined(WEBRTC_HAS_NEON)
63 // Verifies that the optimized methods for filter adaptation are similar to
64 // their reference counterparts.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,FilterAdaptationNeonOptimizations)65 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
66        FilterAdaptationNeonOptimizations) {
67   const size_t num_render_channels = GetParam();
68   for (size_t num_partitions : {2, 5, 12, 30, 50}) {
69     constexpr int kSampleRateHz = 48000;
70     constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
71 
72     std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
73         RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
74                                   num_render_channels));
75     Random random_generator(42U);
76     std::vector<std::vector<std::vector<float>>> x(
77         kNumBands,
78         std::vector<std::vector<float>>(num_render_channels,
79                                         std::vector<float>(kBlockSize, 0.f)));
80     FftData S_C;
81     FftData S_Neon;
82     FftData G;
83     Aec3Fft fft;
84     std::vector<std::vector<FftData>> H_C(
85         num_partitions, std::vector<FftData>(num_render_channels));
86     std::vector<std::vector<FftData>> H_Neon(
87         num_partitions, std::vector<FftData>(num_render_channels));
88     for (size_t p = 0; p < num_partitions; ++p) {
89       for (size_t ch = 0; ch < num_render_channels; ++ch) {
90         H_C[p][ch].Clear();
91         H_Neon[p][ch].Clear();
92       }
93     }
94 
95     for (size_t k = 0; k < 30; ++k) {
96       for (size_t band = 0; band < x.size(); ++band) {
97         for (size_t ch = 0; ch < x[band].size(); ++ch) {
98           RandomizeSampleVector(&random_generator, x[band][ch]);
99         }
100       }
101       render_delay_buffer->Insert(x);
102       if (k == 0) {
103         render_delay_buffer->Reset();
104       }
105       render_delay_buffer->PrepareCaptureProcessing();
106     }
107     auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
108 
109     for (size_t j = 0; j < G.re.size(); ++j) {
110       G.re[j] = j / 10001.f;
111     }
112     for (size_t j = 1; j < G.im.size() - 1; ++j) {
113       G.im[j] = j / 20001.f;
114     }
115     G.im[0] = 0.f;
116     G.im[G.im.size() - 1] = 0.f;
117 
118     AdaptPartitions_Neon(*render_buffer, G, num_partitions, &H_Neon);
119     AdaptPartitions(*render_buffer, G, num_partitions, &H_C);
120     AdaptPartitions_Neon(*render_buffer, G, num_partitions, &H_Neon);
121     AdaptPartitions(*render_buffer, G, num_partitions, &H_C);
122 
123     for (size_t p = 0; p < num_partitions; ++p) {
124       for (size_t ch = 0; ch < num_render_channels; ++ch) {
125         for (size_t j = 0; j < H_C[p][ch].re.size(); ++j) {
126           EXPECT_FLOAT_EQ(H_C[p][ch].re[j], H_Neon[p][ch].re[j]);
127           EXPECT_FLOAT_EQ(H_C[p][ch].im[j], H_Neon[p][ch].im[j]);
128         }
129       }
130     }
131 
132     ApplyFilter_Neon(*render_buffer, num_partitions, H_Neon, &S_Neon);
133     ApplyFilter(*render_buffer, num_partitions, H_C, &S_C);
134     for (size_t j = 0; j < S_C.re.size(); ++j) {
135       EXPECT_NEAR(S_C.re[j], S_Neon.re[j], fabs(S_C.re[j] * 0.00001f));
136       EXPECT_NEAR(S_C.im[j], S_Neon.im[j], fabs(S_C.re[j] * 0.00001f));
137     }
138   }
139 }
140 
141 // Verifies that the optimized method for frequency response computation is
142 // bitexact to the reference counterpart.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,ComputeFrequencyResponseNeonOptimization)143 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
144        ComputeFrequencyResponseNeonOptimization) {
145   const size_t num_render_channels = GetParam();
146   for (size_t num_partitions : {2, 5, 12, 30, 50}) {
147     std::vector<std::vector<FftData>> H(
148         num_partitions, std::vector<FftData>(num_render_channels));
149     std::vector<std::array<float, kFftLengthBy2Plus1>> H2(num_partitions);
150     std::vector<std::array<float, kFftLengthBy2Plus1>> H2_Neon(num_partitions);
151 
152     for (size_t p = 0; p < num_partitions; ++p) {
153       for (size_t ch = 0; ch < num_render_channels; ++ch) {
154         for (size_t k = 0; k < H[p][ch].re.size(); ++k) {
155           H[p][ch].re[k] = k + p / 3.f + ch;
156           H[p][ch].im[k] = p + k / 7.f - ch;
157         }
158       }
159     }
160 
161     ComputeFrequencyResponse(num_partitions, H, &H2);
162     ComputeFrequencyResponse_Neon(num_partitions, H, &H2_Neon);
163 
164     for (size_t p = 0; p < num_partitions; ++p) {
165       for (size_t k = 0; k < H2[p].size(); ++k) {
166         EXPECT_FLOAT_EQ(H2[p][k], H2_Neon[p][k]);
167       }
168     }
169   }
170 }
171 #endif
172 
173 #if defined(WEBRTC_ARCH_X86_FAMILY)
174 // Verifies that the optimized methods for filter adaptation are bitexact to
175 // their reference counterparts.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,FilterAdaptationSse2Optimizations)176 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
177        FilterAdaptationSse2Optimizations) {
178   const size_t num_render_channels = GetParam();
179   constexpr int kSampleRateHz = 48000;
180   constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
181 
182   bool use_sse2 = (GetCPUInfo(kSSE2) != 0);
183   if (use_sse2) {
184     for (size_t num_partitions : {2, 5, 12, 30, 50}) {
185       std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
186           RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
187                                     num_render_channels));
188       Random random_generator(42U);
189       std::vector<std::vector<std::vector<float>>> x(
190           kNumBands,
191           std::vector<std::vector<float>>(num_render_channels,
192                                           std::vector<float>(kBlockSize, 0.f)));
193       FftData S_C;
194       FftData S_Sse2;
195       FftData G;
196       Aec3Fft fft;
197       std::vector<std::vector<FftData>> H_C(
198           num_partitions, std::vector<FftData>(num_render_channels));
199       std::vector<std::vector<FftData>> H_Sse2(
200           num_partitions, std::vector<FftData>(num_render_channels));
201       for (size_t p = 0; p < num_partitions; ++p) {
202         for (size_t ch = 0; ch < num_render_channels; ++ch) {
203           H_C[p][ch].Clear();
204           H_Sse2[p][ch].Clear();
205         }
206       }
207 
208       for (size_t k = 0; k < 500; ++k) {
209         for (size_t band = 0; band < x.size(); ++band) {
210           for (size_t ch = 0; ch < x[band].size(); ++ch) {
211             RandomizeSampleVector(&random_generator, x[band][ch]);
212           }
213         }
214         render_delay_buffer->Insert(x);
215         if (k == 0) {
216           render_delay_buffer->Reset();
217         }
218         render_delay_buffer->PrepareCaptureProcessing();
219         auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
220 
221         ApplyFilter_Sse2(*render_buffer, num_partitions, H_Sse2, &S_Sse2);
222         ApplyFilter(*render_buffer, num_partitions, H_C, &S_C);
223         for (size_t j = 0; j < S_C.re.size(); ++j) {
224           EXPECT_FLOAT_EQ(S_C.re[j], S_Sse2.re[j]);
225           EXPECT_FLOAT_EQ(S_C.im[j], S_Sse2.im[j]);
226         }
227 
228         std::for_each(G.re.begin(), G.re.end(),
229                       [&](float& a) { a = random_generator.Rand<float>(); });
230         std::for_each(G.im.begin(), G.im.end(),
231                       [&](float& a) { a = random_generator.Rand<float>(); });
232 
233         AdaptPartitions_Sse2(*render_buffer, G, num_partitions, &H_Sse2);
234         AdaptPartitions(*render_buffer, G, num_partitions, &H_C);
235 
236         for (size_t p = 0; p < num_partitions; ++p) {
237           for (size_t ch = 0; ch < num_render_channels; ++ch) {
238             for (size_t j = 0; j < H_C[p][ch].re.size(); ++j) {
239               EXPECT_FLOAT_EQ(H_C[p][ch].re[j], H_Sse2[p][ch].re[j]);
240               EXPECT_FLOAT_EQ(H_C[p][ch].im[j], H_Sse2[p][ch].im[j]);
241             }
242           }
243         }
244       }
245     }
246   }
247 }
248 
249 // Verifies that the optimized methods for filter adaptation are bitexact to
250 // their reference counterparts.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,FilterAdaptationAvx2Optimizations)251 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
252        FilterAdaptationAvx2Optimizations) {
253   const size_t num_render_channels = GetParam();
254   constexpr int kSampleRateHz = 48000;
255   constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
256 
257   bool use_avx2 = (GetCPUInfo(kAVX2) != 0);
258   if (use_avx2) {
259     for (size_t num_partitions : {2, 5, 12, 30, 50}) {
260       std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
261           RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
262                                     num_render_channels));
263       Random random_generator(42U);
264       std::vector<std::vector<std::vector<float>>> x(
265           kNumBands,
266           std::vector<std::vector<float>>(num_render_channels,
267                                           std::vector<float>(kBlockSize, 0.f)));
268       FftData S_C;
269       FftData S_Avx2;
270       FftData G;
271       Aec3Fft fft;
272       std::vector<std::vector<FftData>> H_C(
273           num_partitions, std::vector<FftData>(num_render_channels));
274       std::vector<std::vector<FftData>> H_Avx2(
275           num_partitions, std::vector<FftData>(num_render_channels));
276       for (size_t p = 0; p < num_partitions; ++p) {
277         for (size_t ch = 0; ch < num_render_channels; ++ch) {
278           H_C[p][ch].Clear();
279           H_Avx2[p][ch].Clear();
280         }
281       }
282 
283       for (size_t k = 0; k < 500; ++k) {
284         for (size_t band = 0; band < x.size(); ++band) {
285           for (size_t ch = 0; ch < x[band].size(); ++ch) {
286             RandomizeSampleVector(&random_generator, x[band][ch]);
287           }
288         }
289         render_delay_buffer->Insert(x);
290         if (k == 0) {
291           render_delay_buffer->Reset();
292         }
293         render_delay_buffer->PrepareCaptureProcessing();
294         auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
295 
296         ApplyFilter_Avx2(*render_buffer, num_partitions, H_Avx2, &S_Avx2);
297         ApplyFilter(*render_buffer, num_partitions, H_C, &S_C);
298         for (size_t j = 0; j < S_C.re.size(); ++j) {
299           EXPECT_FLOAT_EQ(S_C.re[j], S_Avx2.re[j]);
300           EXPECT_FLOAT_EQ(S_C.im[j], S_Avx2.im[j]);
301         }
302 
303         std::for_each(G.re.begin(), G.re.end(),
304                       [&](float& a) { a = random_generator.Rand<float>(); });
305         std::for_each(G.im.begin(), G.im.end(),
306                       [&](float& a) { a = random_generator.Rand<float>(); });
307 
308         AdaptPartitions_Avx2(*render_buffer, G, num_partitions, &H_Avx2);
309         AdaptPartitions(*render_buffer, G, num_partitions, &H_C);
310 
311         for (size_t p = 0; p < num_partitions; ++p) {
312           for (size_t ch = 0; ch < num_render_channels; ++ch) {
313             for (size_t j = 0; j < H_C[p][ch].re.size(); ++j) {
314               EXPECT_FLOAT_EQ(H_C[p][ch].re[j], H_Avx2[p][ch].re[j]);
315               EXPECT_FLOAT_EQ(H_C[p][ch].im[j], H_Avx2[p][ch].im[j]);
316             }
317           }
318         }
319       }
320     }
321   }
322 }
323 
324 // Verifies that the optimized method for frequency response computation is
325 // bitexact to the reference counterpart.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,ComputeFrequencyResponseSse2Optimization)326 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
327        ComputeFrequencyResponseSse2Optimization) {
328   const size_t num_render_channels = GetParam();
329   bool use_sse2 = (GetCPUInfo(kSSE2) != 0);
330   if (use_sse2) {
331     for (size_t num_partitions : {2, 5, 12, 30, 50}) {
332       std::vector<std::vector<FftData>> H(
333           num_partitions, std::vector<FftData>(num_render_channels));
334       std::vector<std::array<float, kFftLengthBy2Plus1>> H2(num_partitions);
335       std::vector<std::array<float, kFftLengthBy2Plus1>> H2_Sse2(
336           num_partitions);
337 
338       for (size_t p = 0; p < num_partitions; ++p) {
339         for (size_t ch = 0; ch < num_render_channels; ++ch) {
340           for (size_t k = 0; k < H[p][ch].re.size(); ++k) {
341             H[p][ch].re[k] = k + p / 3.f + ch;
342             H[p][ch].im[k] = p + k / 7.f - ch;
343           }
344         }
345       }
346 
347       ComputeFrequencyResponse(num_partitions, H, &H2);
348       ComputeFrequencyResponse_Sse2(num_partitions, H, &H2_Sse2);
349 
350       for (size_t p = 0; p < num_partitions; ++p) {
351         for (size_t k = 0; k < H2[p].size(); ++k) {
352           EXPECT_FLOAT_EQ(H2[p][k], H2_Sse2[p][k]);
353         }
354       }
355     }
356   }
357 }
358 
359 // Verifies that the optimized method for frequency response computation is
360 // bitexact to the reference counterpart.
TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,ComputeFrequencyResponseAvx2Optimization)361 TEST_P(AdaptiveFirFilterOneTwoFourEightRenderChannels,
362        ComputeFrequencyResponseAvx2Optimization) {
363   const size_t num_render_channels = GetParam();
364   bool use_avx2 = (GetCPUInfo(kAVX2) != 0);
365   if (use_avx2) {
366     for (size_t num_partitions : {2, 5, 12, 30, 50}) {
367       std::vector<std::vector<FftData>> H(
368           num_partitions, std::vector<FftData>(num_render_channels));
369       std::vector<std::array<float, kFftLengthBy2Plus1>> H2(num_partitions);
370       std::vector<std::array<float, kFftLengthBy2Plus1>> H2_Avx2(
371           num_partitions);
372 
373       for (size_t p = 0; p < num_partitions; ++p) {
374         for (size_t ch = 0; ch < num_render_channels; ++ch) {
375           for (size_t k = 0; k < H[p][ch].re.size(); ++k) {
376             H[p][ch].re[k] = k + p / 3.f + ch;
377             H[p][ch].im[k] = p + k / 7.f - ch;
378           }
379         }
380       }
381 
382       ComputeFrequencyResponse(num_partitions, H, &H2);
383       ComputeFrequencyResponse_Avx2(num_partitions, H, &H2_Avx2);
384 
385       for (size_t p = 0; p < num_partitions; ++p) {
386         for (size_t k = 0; k < H2[p].size(); ++k) {
387           EXPECT_FLOAT_EQ(H2[p][k], H2_Avx2[p][k]);
388         }
389       }
390     }
391   }
392 }
393 
394 #endif
395 
396 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
397 // Verifies that the check for non-null data dumper works.
TEST(AdaptiveFirFilterDeathTest,NullDataDumper)398 TEST(AdaptiveFirFilterDeathTest, NullDataDumper) {
399   EXPECT_DEATH(AdaptiveFirFilter(9, 9, 250, 1, DetectOptimization(), nullptr),
400                "");
401 }
402 
403 // Verifies that the check for non-null filter output works.
TEST(AdaptiveFirFilterDeathTest,NullFilterOutput)404 TEST(AdaptiveFirFilterDeathTest, NullFilterOutput) {
405   ApmDataDumper data_dumper(42);
406   AdaptiveFirFilter filter(9, 9, 250, 1, DetectOptimization(), &data_dumper);
407   std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
408       RenderDelayBuffer::Create(EchoCanceller3Config(), 48000, 1));
409   EXPECT_DEATH(filter.Filter(*render_delay_buffer->GetRenderBuffer(), nullptr),
410                "");
411 }
412 
413 #endif
414 
415 // Verifies that the filter statistics can be accessed when filter statistics
416 // are turned on.
TEST(AdaptiveFirFilterTest,FilterStatisticsAccess)417 TEST(AdaptiveFirFilterTest, FilterStatisticsAccess) {
418   ApmDataDumper data_dumper(42);
419   Aec3Optimization optimization = DetectOptimization();
420   AdaptiveFirFilter filter(9, 9, 250, 1, optimization, &data_dumper);
421   std::vector<std::array<float, kFftLengthBy2Plus1>> H2(
422       filter.max_filter_size_partitions(),
423       std::array<float, kFftLengthBy2Plus1>());
424   for (auto& H2_k : H2) {
425     H2_k.fill(0.f);
426   }
427 
428   std::array<float, kFftLengthBy2Plus1> erl;
429   ComputeErl(optimization, H2, erl);
430   filter.ComputeFrequencyResponse(&H2);
431 }
432 
433 // Verifies that the filter size if correctly repported.
TEST(AdaptiveFirFilterTest,FilterSize)434 TEST(AdaptiveFirFilterTest, FilterSize) {
435   ApmDataDumper data_dumper(42);
436   for (size_t filter_size = 1; filter_size < 5; ++filter_size) {
437     AdaptiveFirFilter filter(filter_size, filter_size, 250, 1,
438                              DetectOptimization(), &data_dumper);
439     EXPECT_EQ(filter_size, filter.SizePartitions());
440   }
441 }
442 
443 class AdaptiveFirFilterMultiChannel
444     : public ::testing::Test,
445       public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};
446 
447 INSTANTIATE_TEST_SUITE_P(MultiChannel,
448                          AdaptiveFirFilterMultiChannel,
449                          ::testing::Combine(::testing::Values(1, 4),
450                                             ::testing::Values(1, 8)));
451 
452 // Verifies that the filter is being able to properly filter a signal and to
453 // adapt its coefficients.
TEST_P(AdaptiveFirFilterMultiChannel,FilterAndAdapt)454 TEST_P(AdaptiveFirFilterMultiChannel, FilterAndAdapt) {
455   const size_t num_render_channels = std::get<0>(GetParam());
456   const size_t num_capture_channels = std::get<1>(GetParam());
457 
458   constexpr int kSampleRateHz = 48000;
459   constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
460   constexpr size_t kNumBlocksToProcessPerRenderChannel = 1000;
461 
462   ApmDataDumper data_dumper(42);
463   EchoCanceller3Config config;
464 
465   if (num_render_channels == 33) {
466     config.filter.refined = {13, 0.00005f, 0.0005f, 0.0001f, 2.f, 20075344.f};
467     config.filter.coarse = {13, 0.1f, 20075344.f};
468     config.filter.refined_initial = {12, 0.005f, 0.5f, 0.001f, 2.f, 20075344.f};
469     config.filter.coarse_initial = {12, 0.7f, 20075344.f};
470   }
471 
472   AdaptiveFirFilter filter(
473       config.filter.refined.length_blocks, config.filter.refined.length_blocks,
474       config.filter.config_change_duration_blocks, num_render_channels,
475       DetectOptimization(), &data_dumper);
476   std::vector<std::vector<std::array<float, kFftLengthBy2Plus1>>> H2(
477       num_capture_channels, std::vector<std::array<float, kFftLengthBy2Plus1>>(
478                                 filter.max_filter_size_partitions(),
479                                 std::array<float, kFftLengthBy2Plus1>()));
480   std::vector<std::vector<float>> h(
481       num_capture_channels,
482       std::vector<float>(
483           GetTimeDomainLength(filter.max_filter_size_partitions()), 0.f));
484   Aec3Fft fft;
485   config.delay.default_delay = 1;
486   std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
487       RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
488   CoarseFilterUpdateGain gain(config.filter.coarse,
489                               config.filter.config_change_duration_blocks);
490   Random random_generator(42U);
491   std::vector<std::vector<std::vector<float>>> x(
492       kNumBands, std::vector<std::vector<float>>(
493                      num_render_channels, std::vector<float>(kBlockSize, 0.f)));
494   std::vector<float> n(kBlockSize, 0.f);
495   std::vector<float> y(kBlockSize, 0.f);
496   AecState aec_state(EchoCanceller3Config{}, num_capture_channels);
497   RenderSignalAnalyzer render_signal_analyzer(config);
498   absl::optional<DelayEstimate> delay_estimate;
499   std::vector<float> e(kBlockSize, 0.f);
500   std::array<float, kFftLength> s_scratch;
501   std::vector<SubtractorOutput> output(num_capture_channels);
502   FftData S;
503   FftData G;
504   FftData E;
505   std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(num_capture_channels);
506   std::vector<std::array<float, kFftLengthBy2Plus1>> E2_refined(
507       num_capture_channels);
508   std::array<float, kFftLengthBy2Plus1> E2_coarse;
509   // [B,A] = butter(2,100/8000,'high')
510   constexpr CascadedBiQuadFilter::BiQuadCoefficients
511       kHighPassFilterCoefficients = {{0.97261f, -1.94523f, 0.97261f},
512                                      {-1.94448f, 0.94598f}};
513   for (auto& Y2_ch : Y2) {
514     Y2_ch.fill(0.f);
515   }
516   for (auto& E2_refined_ch : E2_refined) {
517     E2_refined_ch.fill(0.f);
518   }
519   E2_coarse.fill(0.f);
520   for (auto& subtractor_output : output) {
521     subtractor_output.Reset();
522   }
523 
524   constexpr float kScale = 1.0f / kFftLengthBy2;
525 
526   for (size_t delay_samples : {0, 64, 150, 200, 301}) {
527     std::vector<DelayBuffer<float>> delay_buffer(
528         num_render_channels, DelayBuffer<float>(delay_samples));
529     std::vector<std::unique_ptr<CascadedBiQuadFilter>> x_hp_filter(
530         num_render_channels);
531     for (size_t ch = 0; ch < num_render_channels; ++ch) {
532       x_hp_filter[ch] = std::make_unique<CascadedBiQuadFilter>(
533           kHighPassFilterCoefficients, 1);
534     }
535     CascadedBiQuadFilter y_hp_filter(kHighPassFilterCoefficients, 1);
536 
537     SCOPED_TRACE(ProduceDebugText(num_render_channels, delay_samples));
538     const size_t num_blocks_to_process =
539         kNumBlocksToProcessPerRenderChannel * num_render_channels;
540     for (size_t j = 0; j < num_blocks_to_process; ++j) {
541       std::fill(y.begin(), y.end(), 0.f);
542       for (size_t ch = 0; ch < num_render_channels; ++ch) {
543         RandomizeSampleVector(&random_generator, x[0][ch]);
544         std::array<float, kBlockSize> y_channel;
545         delay_buffer[ch].Delay(x[0][ch], y_channel);
546         for (size_t k = 0; k < y.size(); ++k) {
547           y[k] += y_channel[k] / num_render_channels;
548         }
549       }
550 
551       RandomizeSampleVector(&random_generator, n);
552       const float noise_scaling = 1.f / 100.f / num_render_channels;
553       for (size_t k = 0; k < y.size(); ++k) {
554         y[k] += n[k] * noise_scaling;
555       }
556 
557       for (size_t ch = 0; ch < num_render_channels; ++ch) {
558         x_hp_filter[ch]->Process(x[0][ch]);
559       }
560       y_hp_filter.Process(y);
561 
562       render_delay_buffer->Insert(x);
563       if (j == 0) {
564         render_delay_buffer->Reset();
565       }
566       render_delay_buffer->PrepareCaptureProcessing();
567       auto* const render_buffer = render_delay_buffer->GetRenderBuffer();
568 
569       render_signal_analyzer.Update(*render_buffer,
570                                     aec_state.MinDirectPathFilterDelay());
571 
572       filter.Filter(*render_buffer, &S);
573       fft.Ifft(S, &s_scratch);
574       std::transform(y.begin(), y.end(), s_scratch.begin() + kFftLengthBy2,
575                      e.begin(),
576                      [&](float a, float b) { return a - b * kScale; });
577       std::for_each(e.begin(), e.end(),
578                     [](float& a) { a = rtc::SafeClamp(a, -32768.f, 32767.f); });
579       fft.ZeroPaddedFft(e, Aec3Fft::Window::kRectangular, &E);
580       for (auto& o : output) {
581         for (size_t k = 0; k < kBlockSize; ++k) {
582           o.s_refined[k] = kScale * s_scratch[k + kFftLengthBy2];
583         }
584       }
585 
586       std::array<float, kFftLengthBy2Plus1> render_power;
587       render_buffer->SpectralSum(filter.SizePartitions(), &render_power);
588       gain.Compute(render_power, render_signal_analyzer, E,
589                    filter.SizePartitions(), false, &G);
590       filter.Adapt(*render_buffer, G, &h[0]);
591       aec_state.HandleEchoPathChange(EchoPathVariability(
592           false, EchoPathVariability::DelayAdjustment::kNone, false));
593 
594       filter.ComputeFrequencyResponse(&H2[0]);
595       aec_state.Update(delay_estimate, H2, h, *render_buffer, E2_refined, Y2,
596                        output);
597     }
598     // Verify that the filter is able to perform well.
599     EXPECT_LT(1000 * std::inner_product(e.begin(), e.end(), e.begin(), 0.f),
600               std::inner_product(y.begin(), y.end(), y.begin(), 0.f));
601   }
602 }
603 
604 }  // namespace aec3
605 }  // namespace webrtc
606