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/echo_path_delay_estimator.h"
12
13 #include <algorithm>
14 #include <string>
15
16 #include "api/audio/echo_canceller3_config.h"
17 #include "modules/audio_processing/aec3/aec3_common.h"
18 #include "modules/audio_processing/aec3/render_delay_buffer.h"
19 #include "modules/audio_processing/logging/apm_data_dumper.h"
20 #include "modules/audio_processing/test/echo_canceller_test_tools.h"
21 #include "rtc_base/random.h"
22 #include "rtc_base/strings/string_builder.h"
23 #include "test/gtest.h"
24
25 namespace webrtc {
26 namespace {
27
ProduceDebugText(size_t delay,size_t down_sampling_factor)28 std::string ProduceDebugText(size_t delay, size_t down_sampling_factor) {
29 rtc::StringBuilder ss;
30 ss << "Delay: " << delay;
31 ss << ", Down sampling factor: " << down_sampling_factor;
32 return ss.Release();
33 }
34
35 } // namespace
36
37 class EchoPathDelayEstimatorMultiChannel
38 : public ::testing::Test,
39 public ::testing::WithParamInterface<std::tuple<size_t, size_t>> {};
40
41 INSTANTIATE_TEST_SUITE_P(MultiChannel,
42 EchoPathDelayEstimatorMultiChannel,
43 ::testing::Combine(::testing::Values(1, 2, 3, 6, 8),
44 ::testing::Values(1, 2, 4)));
45
46 // Verifies that the basic API calls work.
TEST_P(EchoPathDelayEstimatorMultiChannel,BasicApiCalls)47 TEST_P(EchoPathDelayEstimatorMultiChannel, BasicApiCalls) {
48 const size_t num_render_channels = std::get<0>(GetParam());
49 const size_t num_capture_channels = std::get<1>(GetParam());
50 constexpr int kSampleRateHz = 48000;
51 constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
52 ApmDataDumper data_dumper(0);
53 EchoCanceller3Config config;
54 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
55 RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
56 EchoPathDelayEstimator estimator(&data_dumper, config, num_capture_channels);
57 Block render(kNumBands, num_render_channels);
58 Block capture(/*num_bands=*/1, num_capture_channels);
59 for (size_t k = 0; k < 100; ++k) {
60 render_delay_buffer->Insert(render);
61 estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
62 capture);
63 }
64 }
65
66 // Verifies that the delay estimator produces correct delay for artificially
67 // delayed signals.
TEST(EchoPathDelayEstimator,DelayEstimation)68 TEST(EchoPathDelayEstimator, DelayEstimation) {
69 constexpr size_t kNumRenderChannels = 1;
70 constexpr size_t kNumCaptureChannels = 1;
71 constexpr int kSampleRateHz = 48000;
72 constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
73 Random random_generator(42U);
74 Block render(kNumBands, kNumRenderChannels);
75 Block capture(/*num_bands=*/1, kNumCaptureChannels);
76 ApmDataDumper data_dumper(0);
77 constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
78 for (auto down_sampling_factor : kDownSamplingFactors) {
79 EchoCanceller3Config config;
80 config.delay.delay_headroom_samples = 0;
81 config.delay.down_sampling_factor = down_sampling_factor;
82 config.delay.num_filters = 10;
83 for (size_t delay_samples : {30, 64, 150, 200, 800, 4000}) {
84 SCOPED_TRACE(ProduceDebugText(delay_samples, down_sampling_factor));
85 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
86 RenderDelayBuffer::Create(config, kSampleRateHz, kNumRenderChannels));
87 DelayBuffer<float> signal_delay_buffer(delay_samples);
88 EchoPathDelayEstimator estimator(&data_dumper, config,
89 kNumCaptureChannels);
90
91 absl::optional<DelayEstimate> estimated_delay_samples;
92 for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) {
93 RandomizeSampleVector(&random_generator,
94 render.View(/*band=*/0, /*channel=*/0));
95 signal_delay_buffer.Delay(render.View(/*band=*/0, /*channel=*/0),
96 capture.View(/*band=*/0, /*channel=*/0));
97 render_delay_buffer->Insert(render);
98
99 if (k == 0) {
100 render_delay_buffer->Reset();
101 }
102
103 render_delay_buffer->PrepareCaptureProcessing();
104
105 auto estimate = estimator.EstimateDelay(
106 render_delay_buffer->GetDownsampledRenderBuffer(), capture);
107
108 if (estimate) {
109 estimated_delay_samples = estimate;
110 }
111 }
112
113 if (estimated_delay_samples) {
114 // Allow estimated delay to be off by a block as internally the delay is
115 // quantized with an error up to a block.
116 size_t delay_ds = delay_samples / down_sampling_factor;
117 size_t estimated_delay_ds =
118 estimated_delay_samples->delay / down_sampling_factor;
119 EXPECT_NEAR(delay_ds, estimated_delay_ds,
120 kBlockSize / down_sampling_factor);
121 } else {
122 ADD_FAILURE();
123 }
124 }
125 }
126 }
127
128 // Verifies that the delay estimator does not produce delay estimates for render
129 // signals of low level.
TEST(EchoPathDelayEstimator,NoDelayEstimatesForLowLevelRenderSignals)130 TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) {
131 constexpr size_t kNumRenderChannels = 1;
132 constexpr size_t kNumCaptureChannels = 1;
133 constexpr int kSampleRateHz = 48000;
134 constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
135 Random random_generator(42U);
136 EchoCanceller3Config config;
137 Block render(kNumBands, kNumRenderChannels);
138 Block capture(/*num_bands=*/1, kNumCaptureChannels);
139 ApmDataDumper data_dumper(0);
140 EchoPathDelayEstimator estimator(&data_dumper, config, kNumCaptureChannels);
141 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
142 RenderDelayBuffer::Create(EchoCanceller3Config(), kSampleRateHz,
143 kNumRenderChannels));
144 for (size_t k = 0; k < 100; ++k) {
145 RandomizeSampleVector(&random_generator,
146 render.View(/*band=*/0, /*channel=*/0));
147 for (auto& render_k : render.View(/*band=*/0, /*channel=*/0)) {
148 render_k *= 100.f / 32767.f;
149 }
150 std::copy(render.begin(/*band=*/0, /*channel=*/0),
151 render.end(/*band=*/0, /*channel=*/0),
152 capture.begin(/*band*/ 0, /*channel=*/0));
153 render_delay_buffer->Insert(render);
154 render_delay_buffer->PrepareCaptureProcessing();
155 EXPECT_FALSE(estimator.EstimateDelay(
156 render_delay_buffer->GetDownsampledRenderBuffer(), capture));
157 }
158 }
159
160 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
161
162 // Verifies the check for the render blocksize.
163 // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
164 // tests on test bots has been fixed.
TEST(EchoPathDelayEstimatorDeathTest,DISABLED_WrongRenderBlockSize)165 TEST(EchoPathDelayEstimatorDeathTest, DISABLED_WrongRenderBlockSize) {
166 ApmDataDumper data_dumper(0);
167 EchoCanceller3Config config;
168 EchoPathDelayEstimator estimator(&data_dumper, config, 1);
169 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
170 RenderDelayBuffer::Create(config, 48000, 1));
171 Block capture(/*num_bands=*/1, /*num_channels=*/1);
172 EXPECT_DEATH(estimator.EstimateDelay(
173 render_delay_buffer->GetDownsampledRenderBuffer(), capture),
174 "");
175 }
176
177 // Verifies the check for non-null data dumper.
TEST(EchoPathDelayEstimatorDeathTest,NullDataDumper)178 TEST(EchoPathDelayEstimatorDeathTest, NullDataDumper) {
179 EXPECT_DEATH(EchoPathDelayEstimator(nullptr, EchoCanceller3Config(), 1), "");
180 }
181
182 #endif
183
184 } // namespace webrtc
185