blob: 8d9199c8306b6c2d5004050337a51ca8fe6bc9a3 [file] [log] [blame]
peahd0263542017-01-03 04:20:34 -08001/*
2 * Copyright (c) 2016 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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/aec3/echo_canceller3.h"
peahd0263542017-01-03 04:20:34 -080012
13#include <deque>
14#include <memory>
peahd0263542017-01-03 04:20:34 -080015#include <string>
16#include <utility>
17#include <vector>
18
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_processing/aec3/aec3_common.h"
20#include "modules/audio_processing/aec3/block_processor.h"
21#include "modules/audio_processing/aec3/frame_blocker.h"
22#include "modules/audio_processing/aec3/mock/mock_block_processor.h"
23#include "modules/audio_processing/audio_buffer.h"
Per Åhgren0aefbf02019-08-23 21:29:17 +020024#include "modules/audio_processing/high_pass_filter.h"
25#include "modules/audio_processing/utility/cascaded_biquad_filter.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020026#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "test/gmock.h"
28#include "test/gtest.h"
peahd0263542017-01-03 04:20:34 -080029
30namespace webrtc {
31namespace {
32
Mirko Bonadei6a489f22019-04-09 15:11:12 +020033using ::testing::_;
34using ::testing::StrictMock;
peahd0263542017-01-03 04:20:34 -080035
36// Populates the frame with linearly increasing sample values for each band,
37// with a band-specific offset, in order to allow simple bitexactness
38// verification for each band.
39void PopulateInputFrame(size_t frame_length,
40 size_t num_bands,
41 size_t frame_index,
42 float* const* frame,
43 int offset) {
44 for (size_t k = 0; k < num_bands; ++k) {
45 for (size_t i = 0; i < frame_length; ++i) {
46 float value = static_cast<int>(frame_index * frame_length + i) + offset;
47 frame[k][i] = (value > 0 ? 5000 * k + value : 0);
48 }
49 }
50}
51
peah522d71b2017-02-23 05:16:26 -080052// Populates the frame with linearly increasing sample values.
53void PopulateInputFrame(size_t frame_length,
54 size_t frame_index,
55 float* frame,
56 int offset) {
57 for (size_t i = 0; i < frame_length; ++i) {
58 float value = static_cast<int>(frame_index * frame_length + i) + offset;
59 frame[i] = std::max(value, 0.f);
60 }
61}
62
peahd0263542017-01-03 04:20:34 -080063// Verifies the that samples in the output frame are identical to the samples
64// that were produced for the input frame, with an offset in order to compensate
65// for buffering delays.
66bool VerifyOutputFrameBitexactness(size_t frame_length,
67 size_t num_bands,
68 size_t frame_index,
69 const float* const* frame,
70 int offset) {
71 float reference_frame_data[kMaxNumBands][2 * kSubFrameLength];
72 float* reference_frame[kMaxNumBands];
73 for (size_t k = 0; k < num_bands; ++k) {
74 reference_frame[k] = &reference_frame_data[k][0];
75 }
76
77 PopulateInputFrame(frame_length, num_bands, frame_index, reference_frame,
78 offset);
79 for (size_t k = 0; k < num_bands; ++k) {
80 for (size_t i = 0; i < frame_length; ++i) {
81 if (reference_frame[k][i] != frame[k][i]) {
82 return false;
83 }
84 }
85 }
86
87 return true;
88}
89
Per Åhgren0aefbf02019-08-23 21:29:17 +020090bool VerifyOutputFrameBitexactness(rtc::ArrayView<const float> reference,
91 rtc::ArrayView<const float> frame,
92 int offset) {
93 for (size_t k = 0; k < frame.size(); ++k) {
94 int reference_index = static_cast<int>(k) + offset;
95 if (reference_index >= 0) {
96 if (reference[reference_index] != frame[k]) {
97 return false;
98 }
99 }
100 }
101 return true;
102}
103
peahd0263542017-01-03 04:20:34 -0800104// Class for testing that the capture data is properly received by the block
105// processor and that the processor data is properly passed to the
106// EchoCanceller3 output.
107class CaptureTransportVerificationProcessor : public BlockProcessor {
108 public:
109 explicit CaptureTransportVerificationProcessor(size_t num_bands) {}
110 ~CaptureTransportVerificationProcessor() override = default;
111
Per Åhgrence202a02019-09-02 17:01:19 +0200112 void ProcessCapture(
113 bool level_change,
114 bool saturated_microphone_signal,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100115 std::vector<std::vector<std::vector<float>>>* linear_output,
Per Åhgrence202a02019-09-02 17:01:19 +0200116 std::vector<std::vector<std::vector<float>>>* capture_block) override {}
peahd0263542017-01-03 04:20:34 -0800117
Per Åhgrence202a02019-09-02 17:01:19 +0200118 void BufferRender(
119 const std::vector<std::vector<std::vector<float>>>& block) override {}
peahd0263542017-01-03 04:20:34 -0800120
peah69221db2017-01-27 03:28:19 -0800121 void UpdateEchoLeakageStatus(bool leakage_detected) override {}
peahd0263542017-01-03 04:20:34 -0800122
Gustaf Ullberg332150d2017-11-22 14:17:39 +0100123 void GetMetrics(EchoControl::Metrics* metrics) const override {}
124
Gustaf Ullberg3cb61042019-10-24 15:52:10 +0200125 void SetAudioBufferDelay(int delay_ms) override {}
Per Åhgrend0fa8202018-04-18 09:35:13 +0200126
peahd0263542017-01-03 04:20:34 -0800127 private:
128 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTransportVerificationProcessor);
129};
130
131// Class for testing that the render data is properly received by the block
132// processor.
133class RenderTransportVerificationProcessor : public BlockProcessor {
134 public:
135 explicit RenderTransportVerificationProcessor(size_t num_bands) {}
136 ~RenderTransportVerificationProcessor() override = default;
137
Per Åhgrence202a02019-09-02 17:01:19 +0200138 void ProcessCapture(
139 bool level_change,
140 bool saturated_microphone_signal,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100141 std::vector<std::vector<std::vector<float>>>* linear_output,
Per Åhgrence202a02019-09-02 17:01:19 +0200142 std::vector<std::vector<std::vector<float>>>* capture_block) override {
143 std::vector<std::vector<std::vector<float>>> render_block =
peahd0263542017-01-03 04:20:34 -0800144 received_render_blocks_.front();
145 received_render_blocks_.pop_front();
146 capture_block->swap(render_block);
147 }
148
Per Åhgrence202a02019-09-02 17:01:19 +0200149 void BufferRender(
150 const std::vector<std::vector<std::vector<float>>>& block) override {
peahcf02cf12017-04-05 14:18:07 -0700151 received_render_blocks_.push_back(block);
peahd0263542017-01-03 04:20:34 -0800152 }
153
peah69221db2017-01-27 03:28:19 -0800154 void UpdateEchoLeakageStatus(bool leakage_detected) override {}
peahd0263542017-01-03 04:20:34 -0800155
Gustaf Ullberg332150d2017-11-22 14:17:39 +0100156 void GetMetrics(EchoControl::Metrics* metrics) const override {}
157
Gustaf Ullberg3cb61042019-10-24 15:52:10 +0200158 void SetAudioBufferDelay(int delay_ms) override {}
Per Åhgrend0fa8202018-04-18 09:35:13 +0200159
peahd0263542017-01-03 04:20:34 -0800160 private:
Per Åhgrence202a02019-09-02 17:01:19 +0200161 std::deque<std::vector<std::vector<std::vector<float>>>>
162 received_render_blocks_;
peahd0263542017-01-03 04:20:34 -0800163 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderTransportVerificationProcessor);
164};
165
166class EchoCanceller3Tester {
167 public:
168 explicit EchoCanceller3Tester(int sample_rate_hz)
169 : sample_rate_hz_(sample_rate_hz),
170 num_bands_(NumBandsForRate(sample_rate_hz_)),
Per Åhgrence202a02019-09-02 17:01:19 +0200171 frame_length_(160),
peahd0263542017-01-03 04:20:34 -0800172 fullband_frame_length_(rtc::CheckedDivExact(sample_rate_hz_, 100)),
Per Åhgrend47941e2019-08-22 11:51:13 +0200173 capture_buffer_(fullband_frame_length_ * 100,
peahd0263542017-01-03 04:20:34 -0800174 1,
Per Åhgrend47941e2019-08-22 11:51:13 +0200175 fullband_frame_length_ * 100,
peahd0263542017-01-03 04:20:34 -0800176 1,
Per Åhgrend47941e2019-08-22 11:51:13 +0200177 fullband_frame_length_ * 100,
178 1),
179 render_buffer_(fullband_frame_length_ * 100,
peahd0263542017-01-03 04:20:34 -0800180 1,
Per Åhgrend47941e2019-08-22 11:51:13 +0200181 fullband_frame_length_ * 100,
peahd0263542017-01-03 04:20:34 -0800182 1,
Per Åhgrend47941e2019-08-22 11:51:13 +0200183 fullband_frame_length_ * 100,
184 1) {}
peahd0263542017-01-03 04:20:34 -0800185
186 // Verifies that the capture data is properly received by the block processor
187 // and that the processor data is properly passed to the EchoCanceller3
188 // output.
189 void RunCaptureTransportVerificationTest() {
190 EchoCanceller3 aec3(
Per Åhgrence202a02019-09-02 17:01:19 +0200191 EchoCanceller3Config(), sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800192 std::unique_ptr<BlockProcessor>(
193 new CaptureTransportVerificationProcessor(num_bands_)));
194
195 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
196 ++frame_index) {
197 aec3.AnalyzeCapture(&capture_buffer_);
198 OptionalBandSplit();
199 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200200 &capture_buffer_.split_bands(0)[0], 0);
peah522d71b2017-02-23 05:16:26 -0800201 PopulateInputFrame(frame_length_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200202 &render_buffer_.channels()[0][0], 0);
peahd0263542017-01-03 04:20:34 -0800203
peahcf02cf12017-04-05 14:18:07 -0700204 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800205 aec3.ProcessCapture(&capture_buffer_, false);
206 EXPECT_TRUE(VerifyOutputFrameBitexactness(
207 frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200208 &capture_buffer_.split_bands(0)[0], -64));
peahd0263542017-01-03 04:20:34 -0800209 }
210 }
211
212 // Test method for testing that the render data is properly received by the
213 // block processor.
214 void RunRenderTransportVerificationTest() {
215 EchoCanceller3 aec3(
Per Åhgrence202a02019-09-02 17:01:19 +0200216 EchoCanceller3Config(), sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800217 std::unique_ptr<BlockProcessor>(
218 new RenderTransportVerificationProcessor(num_bands_)));
219
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200220 std::vector<std::vector<float>> render_input(1);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200221 std::vector<float> capture_output;
peahd0263542017-01-03 04:20:34 -0800222 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
223 ++frame_index) {
224 aec3.AnalyzeCapture(&capture_buffer_);
225 OptionalBandSplit();
226 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200227 &capture_buffer_.split_bands(0)[0], 100);
peahcf02cf12017-04-05 14:18:07 -0700228 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200229 &render_buffer_.split_bands(0)[0], 0);
peahd0263542017-01-03 04:20:34 -0800230
Per Åhgren0aefbf02019-08-23 21:29:17 +0200231 for (size_t k = 0; k < frame_length_; ++k) {
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200232 render_input[0].push_back(render_buffer_.split_bands(0)[0][k]);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200233 }
peahcf02cf12017-04-05 14:18:07 -0700234 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800235 aec3.ProcessCapture(&capture_buffer_, false);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200236 for (size_t k = 0; k < frame_length_; ++k) {
237 capture_output.push_back(capture_buffer_.split_bands(0)[0][k]);
238 }
peahd0263542017-01-03 04:20:34 -0800239 }
Per Åhgren0aefbf02019-08-23 21:29:17 +0200240 HighPassFilter hp_filter(1);
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200241 hp_filter.Process(&render_input);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200242
243 EXPECT_TRUE(
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200244 VerifyOutputFrameBitexactness(render_input[0], capture_output, -64));
peahd0263542017-01-03 04:20:34 -0800245 }
246
247 // Verifies that information about echo path changes are properly propagated
248 // to the block processor.
249 // The cases tested are:
250 // -That no set echo path change flags are received when there is no echo path
251 // change.
252 // -That set echo path change flags are received and continues to be received
253 // as long as echo path changes are flagged.
254 // -That set echo path change flags are no longer received when echo path
255 // change events stop being flagged.
256 enum class EchoPathChangeTestVariant { kNone, kOneSticky, kOneNonSticky };
257
258 void RunEchoPathChangeVerificationTest(
259 EchoPathChangeTestVariant echo_path_change_test_variant) {
Per Åhgrence202a02019-09-02 17:01:19 +0200260 constexpr size_t kNumFullBlocksPerFrame = 160 / kBlockSize;
261 constexpr size_t kExpectedNumBlocksToProcess =
262 (kNumFramesToProcess * 160) / kBlockSize;
peahd0263542017-01-03 04:20:34 -0800263 std::unique_ptr<testing::StrictMock<webrtc::test::MockBlockProcessor>>
264 block_processor_mock(
265 new StrictMock<webrtc::test::MockBlockProcessor>());
266 EXPECT_CALL(*block_processor_mock, BufferRender(_))
Per Åhgrence202a02019-09-02 17:01:19 +0200267 .Times(kExpectedNumBlocksToProcess);
peah69221db2017-01-27 03:28:19 -0800268 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(_)).Times(0);
peahd0263542017-01-03 04:20:34 -0800269
270 switch (echo_path_change_test_variant) {
271 case EchoPathChangeTestVariant::kNone:
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100272 EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200273 .Times(kExpectedNumBlocksToProcess);
peahd0263542017-01-03 04:20:34 -0800274 break;
275 case EchoPathChangeTestVariant::kOneSticky:
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100276 EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200277 .Times(kExpectedNumBlocksToProcess);
peahd0263542017-01-03 04:20:34 -0800278 break;
279 case EchoPathChangeTestVariant::kOneNonSticky:
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100280 EXPECT_CALL(*block_processor_mock, ProcessCapture(true, _, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200281 .Times(kNumFullBlocksPerFrame);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100282 EXPECT_CALL(*block_processor_mock, ProcessCapture(false, _, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200283 .Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
peahd0263542017-01-03 04:20:34 -0800284 break;
285 }
286
Per Åhgrence202a02019-09-02 17:01:19 +0200287 EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800288 std::move(block_processor_mock));
289
290 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
291 ++frame_index) {
292 bool echo_path_change = false;
293 switch (echo_path_change_test_variant) {
294 case EchoPathChangeTestVariant::kNone:
295 break;
296 case EchoPathChangeTestVariant::kOneSticky:
297 echo_path_change = true;
298 break;
299 case EchoPathChangeTestVariant::kOneNonSticky:
300 if (frame_index == 0) {
301 echo_path_change = true;
302 }
303 break;
304 }
305
306 aec3.AnalyzeCapture(&capture_buffer_);
307 OptionalBandSplit();
308
309 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200310 &capture_buffer_.split_bands(0)[0], 0);
peah522d71b2017-02-23 05:16:26 -0800311 PopulateInputFrame(frame_length_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200312 &render_buffer_.channels()[0][0], 0);
peahd0263542017-01-03 04:20:34 -0800313
peahcf02cf12017-04-05 14:18:07 -0700314 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800315 aec3.ProcessCapture(&capture_buffer_, echo_path_change);
316 }
317 }
318
319 // Test for verifying that echo leakage information is being properly passed
320 // to the processor.
321 // The cases tested are:
322 // -That no method calls are received when they should not.
323 // -That false values are received each time they are flagged.
324 // -That true values are received each time they are flagged.
325 // -That a false value is received when flagged after a true value has been
326 // flagged.
327 enum class EchoLeakageTestVariant {
328 kNone,
329 kFalseSticky,
330 kTrueSticky,
331 kTrueNonSticky
332 };
333
334 void RunEchoLeakageVerificationTest(
335 EchoLeakageTestVariant leakage_report_variant) {
Per Åhgrence202a02019-09-02 17:01:19 +0200336 constexpr size_t kExpectedNumBlocksToProcess =
337 (kNumFramesToProcess * 160) / kBlockSize;
peahd0263542017-01-03 04:20:34 -0800338 std::unique_ptr<testing::StrictMock<webrtc::test::MockBlockProcessor>>
339 block_processor_mock(
340 new StrictMock<webrtc::test::MockBlockProcessor>());
341 EXPECT_CALL(*block_processor_mock, BufferRender(_))
Per Åhgrence202a02019-09-02 17:01:19 +0200342 .Times(kExpectedNumBlocksToProcess);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100343 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, _, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200344 .Times(kExpectedNumBlocksToProcess);
peahd0263542017-01-03 04:20:34 -0800345
346 switch (leakage_report_variant) {
347 case EchoLeakageTestVariant::kNone:
peah69221db2017-01-27 03:28:19 -0800348 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(_)).Times(0);
peahd0263542017-01-03 04:20:34 -0800349 break;
350 case EchoLeakageTestVariant::kFalseSticky:
peah69221db2017-01-27 03:28:19 -0800351 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(false))
352 .Times(1);
peahd0263542017-01-03 04:20:34 -0800353 break;
354 case EchoLeakageTestVariant::kTrueSticky:
peah69221db2017-01-27 03:28:19 -0800355 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(true))
356 .Times(1);
peahd0263542017-01-03 04:20:34 -0800357 break;
358 case EchoLeakageTestVariant::kTrueNonSticky: {
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200359 ::testing::InSequence s;
peah69221db2017-01-27 03:28:19 -0800360 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(true))
361 .Times(1);
362 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(false))
peahd0263542017-01-03 04:20:34 -0800363 .Times(kNumFramesToProcess - 1);
364 } break;
365 }
366
Per Åhgrence202a02019-09-02 17:01:19 +0200367 EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800368 std::move(block_processor_mock));
369
370 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
371 ++frame_index) {
372 switch (leakage_report_variant) {
373 case EchoLeakageTestVariant::kNone:
374 break;
375 case EchoLeakageTestVariant::kFalseSticky:
376 if (frame_index == 0) {
peah69221db2017-01-27 03:28:19 -0800377 aec3.UpdateEchoLeakageStatus(false);
peahd0263542017-01-03 04:20:34 -0800378 }
379 break;
380 case EchoLeakageTestVariant::kTrueSticky:
381 if (frame_index == 0) {
peah69221db2017-01-27 03:28:19 -0800382 aec3.UpdateEchoLeakageStatus(true);
peahd0263542017-01-03 04:20:34 -0800383 }
384 break;
385 case EchoLeakageTestVariant::kTrueNonSticky:
386 if (frame_index == 0) {
peah69221db2017-01-27 03:28:19 -0800387 aec3.UpdateEchoLeakageStatus(true);
peahd0263542017-01-03 04:20:34 -0800388 } else {
peah69221db2017-01-27 03:28:19 -0800389 aec3.UpdateEchoLeakageStatus(false);
peahd0263542017-01-03 04:20:34 -0800390 }
391 break;
392 }
393
394 aec3.AnalyzeCapture(&capture_buffer_);
395 OptionalBandSplit();
396
397 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200398 &capture_buffer_.split_bands(0)[0], 0);
peah522d71b2017-02-23 05:16:26 -0800399 PopulateInputFrame(frame_length_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200400 &render_buffer_.channels()[0][0], 0);
peahd0263542017-01-03 04:20:34 -0800401
peahcf02cf12017-04-05 14:18:07 -0700402 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800403 aec3.ProcessCapture(&capture_buffer_, false);
404 }
405 }
406
407 // This verifies that saturation information is properly passed to the
408 // BlockProcessor.
409 // The cases tested are:
410 // -That no saturation event is passed to the processor if there is no
411 // saturation.
412 // -That one frame with one negative saturated sample value is reported to be
413 // saturated and that following non-saturated frames are properly reported as
414 // not being saturated.
415 // -That one frame with one positive saturated sample value is reported to be
416 // saturated and that following non-saturated frames are properly reported as
417 // not being saturated.
418 enum class SaturationTestVariant { kNone, kOneNegative, kOnePositive };
419
420 void RunCaptureSaturationVerificationTest(
421 SaturationTestVariant saturation_variant) {
Per Åhgrence202a02019-09-02 17:01:19 +0200422 const size_t kNumFullBlocksPerFrame = 160 / kBlockSize;
423 const size_t kExpectedNumBlocksToProcess =
424 (kNumFramesToProcess * 160) / kBlockSize;
peahd0263542017-01-03 04:20:34 -0800425 std::unique_ptr<testing::StrictMock<webrtc::test::MockBlockProcessor>>
426 block_processor_mock(
427 new StrictMock<webrtc::test::MockBlockProcessor>());
428 EXPECT_CALL(*block_processor_mock, BufferRender(_))
Per Åhgrence202a02019-09-02 17:01:19 +0200429 .Times(kExpectedNumBlocksToProcess);
peah69221db2017-01-27 03:28:19 -0800430 EXPECT_CALL(*block_processor_mock, UpdateEchoLeakageStatus(_)).Times(0);
peahd0263542017-01-03 04:20:34 -0800431
432 switch (saturation_variant) {
433 case SaturationTestVariant::kNone:
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100434 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200435 .Times(kExpectedNumBlocksToProcess);
peahd0263542017-01-03 04:20:34 -0800436 break;
437 case SaturationTestVariant::kOneNegative: {
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200438 ::testing::InSequence s;
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100439 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200440 .Times(kNumFullBlocksPerFrame);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100441 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200442 .Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
peahd0263542017-01-03 04:20:34 -0800443 } break;
444 case SaturationTestVariant::kOnePositive: {
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200445 ::testing::InSequence s;
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100446 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, true, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200447 .Times(kNumFullBlocksPerFrame);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100448 EXPECT_CALL(*block_processor_mock, ProcessCapture(_, false, _, _))
Per Åhgrence202a02019-09-02 17:01:19 +0200449 .Times(kExpectedNumBlocksToProcess - kNumFullBlocksPerFrame);
peahd0263542017-01-03 04:20:34 -0800450 } break;
451 }
452
Per Åhgrence202a02019-09-02 17:01:19 +0200453 EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800454 std::move(block_processor_mock));
peahd0263542017-01-03 04:20:34 -0800455 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
456 ++frame_index) {
457 for (int k = 0; k < fullband_frame_length_; ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200458 capture_buffer_.channels()[0][k] = 0.f;
peahd0263542017-01-03 04:20:34 -0800459 }
460 switch (saturation_variant) {
461 case SaturationTestVariant::kNone:
462 break;
463 case SaturationTestVariant::kOneNegative:
464 if (frame_index == 0) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200465 capture_buffer_.channels()[0][10] = -32768.f;
peahd0263542017-01-03 04:20:34 -0800466 }
467 break;
468 case SaturationTestVariant::kOnePositive:
469 if (frame_index == 0) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200470 capture_buffer_.channels()[0][10] = 32767.f;
peahd0263542017-01-03 04:20:34 -0800471 }
472 break;
473 }
474
475 aec3.AnalyzeCapture(&capture_buffer_);
476 OptionalBandSplit();
477
478 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200479 &capture_buffer_.split_bands(0)[0], 0);
peahcf02cf12017-04-05 14:18:07 -0700480 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200481 &render_buffer_.split_bands(0)[0], 0);
peahd0263542017-01-03 04:20:34 -0800482
peahcf02cf12017-04-05 14:18:07 -0700483 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800484 aec3.ProcessCapture(&capture_buffer_, false);
485 }
486 }
487
488 // This test verifies that the swapqueue is able to handle jitter in the
489 // capture and render API calls.
Mirko Bonadeif0d9cda2019-01-17 20:43:58 +0000490 void RunRenderSwapQueueVerificationTest() {
Per Åhgren8ba58612017-12-01 23:01:44 +0100491 const EchoCanceller3Config config;
peahd0263542017-01-03 04:20:34 -0800492 EchoCanceller3 aec3(
Per Åhgrence202a02019-09-02 17:01:19 +0200493 config, sample_rate_hz_, 1, 1,
peahd0263542017-01-03 04:20:34 -0800494 std::unique_ptr<BlockProcessor>(
495 new RenderTransportVerificationProcessor(num_bands_)));
496
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200497 std::vector<std::vector<float>> render_input(1);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200498 std::vector<float> capture_output;
499
Per Åhgren8ba58612017-12-01 23:01:44 +0100500 for (size_t frame_index = 0; frame_index < kRenderTransferQueueSizeFrames;
peahd0263542017-01-03 04:20:34 -0800501 ++frame_index) {
502 if (sample_rate_hz_ > 16000) {
503 render_buffer_.SplitIntoFrequencyBands();
504 }
peahcf02cf12017-04-05 14:18:07 -0700505 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200506 &render_buffer_.split_bands(0)[0], 0);
peahd0263542017-01-03 04:20:34 -0800507
peahcf02cf12017-04-05 14:18:07 -0700508 if (sample_rate_hz_ > 16000) {
509 render_buffer_.SplitIntoFrequencyBands();
510 }
511
Per Åhgren0aefbf02019-08-23 21:29:17 +0200512 for (size_t k = 0; k < frame_length_; ++k) {
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200513 render_input[0].push_back(render_buffer_.split_bands(0)[0][k]);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200514 }
peahcf02cf12017-04-05 14:18:07 -0700515 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800516 }
517
Per Åhgren8ba58612017-12-01 23:01:44 +0100518 for (size_t frame_index = 0; frame_index < kRenderTransferQueueSizeFrames;
peahd0263542017-01-03 04:20:34 -0800519 ++frame_index) {
520 aec3.AnalyzeCapture(&capture_buffer_);
521 if (sample_rate_hz_ > 16000) {
522 capture_buffer_.SplitIntoFrequencyBands();
523 }
524
525 PopulateInputFrame(frame_length_, num_bands_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200526 &capture_buffer_.split_bands(0)[0], 0);
peahd0263542017-01-03 04:20:34 -0800527
528 aec3.ProcessCapture(&capture_buffer_, false);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200529 for (size_t k = 0; k < frame_length_; ++k) {
530 capture_output.push_back(capture_buffer_.split_bands(0)[0][k]);
531 }
peahd0263542017-01-03 04:20:34 -0800532 }
Per Åhgren0aefbf02019-08-23 21:29:17 +0200533 HighPassFilter hp_filter(1);
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200534 hp_filter.Process(&render_input);
Per Åhgren0aefbf02019-08-23 21:29:17 +0200535
536 EXPECT_TRUE(
Sam Zackrissonfeee1e42019-09-20 07:50:35 +0200537 VerifyOutputFrameBitexactness(render_input[0], capture_output, -64));
peahd0263542017-01-03 04:20:34 -0800538 }
539
540 // This test verifies that a buffer overrun in the render swapqueue is
541 // properly reported.
Mirko Bonadeif0d9cda2019-01-17 20:43:58 +0000542 void RunRenderPipelineSwapQueueOverrunReturnValueTest() {
Per Åhgrence202a02019-09-02 17:01:19 +0200543 EchoCanceller3 aec3(EchoCanceller3Config(), sample_rate_hz_, 1, 1);
peahd0263542017-01-03 04:20:34 -0800544
peahcf02cf12017-04-05 14:18:07 -0700545 constexpr size_t kRenderTransferQueueSize = 30;
peahd0263542017-01-03 04:20:34 -0800546 for (size_t k = 0; k < 2; ++k) {
peahcf02cf12017-04-05 14:18:07 -0700547 for (size_t frame_index = 0; frame_index < kRenderTransferQueueSize;
peahd0263542017-01-03 04:20:34 -0800548 ++frame_index) {
549 if (sample_rate_hz_ > 16000) {
550 render_buffer_.SplitIntoFrequencyBands();
551 }
peah522d71b2017-02-23 05:16:26 -0800552 PopulateInputFrame(frame_length_, frame_index,
Per Åhgrend47941e2019-08-22 11:51:13 +0200553 &render_buffer_.channels()[0][0], 0);
peahd0263542017-01-03 04:20:34 -0800554
Per Åhgren0aefbf02019-08-23 21:29:17 +0200555 aec3.AnalyzeRender(&render_buffer_);
peahd0263542017-01-03 04:20:34 -0800556 }
557 }
558 }
559
560#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
561 // Verifies the that the check for the number of bands in the AnalyzeRender
562 // input is correct by adjusting the sample rates of EchoCanceller3 and the
563 // input AudioBuffer to have a different number of bands.
564 void RunAnalyzeRenderNumBandsCheckVerification() {
565 // Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
566 // way that the number of bands for the rates are different.
567 const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000;
Per Åhgrence202a02019-09-02 17:01:19 +0200568 EchoCanceller3 aec3(EchoCanceller3Config(), aec3_sample_rate_hz, 1, 1);
peah522d71b2017-02-23 05:16:26 -0800569 PopulateInputFrame(frame_length_, 0, &render_buffer_.channels_f()[0][0], 0);
peahd0263542017-01-03 04:20:34 -0800570
571 EXPECT_DEATH(aec3.AnalyzeRender(&render_buffer_), "");
572 }
573
574 // Verifies the that the check for the number of bands in the ProcessCapture
575 // input is correct by adjusting the sample rates of EchoCanceller3 and the
576 // input AudioBuffer to have a different number of bands.
577 void RunProcessCaptureNumBandsCheckVerification() {
578 // Set aec3_sample_rate_hz to be different from sample_rate_hz_ in such a
579 // way that the number of bands for the rates are different.
580 const int aec3_sample_rate_hz = sample_rate_hz_ == 48000 ? 32000 : 48000;
Per Åhgrence202a02019-09-02 17:01:19 +0200581 EchoCanceller3 aec3(EchoCanceller3Config(), aec3_sample_rate_hz, 1, 1);
peahd0263542017-01-03 04:20:34 -0800582 PopulateInputFrame(frame_length_, num_bands_, 0,
583 &capture_buffer_.split_bands_f(0)[0], 100);
584 EXPECT_DEATH(aec3.ProcessCapture(&capture_buffer_, false), "");
585 }
586
peahd0263542017-01-03 04:20:34 -0800587#endif
588
589 private:
590 void OptionalBandSplit() {
591 if (sample_rate_hz_ > 16000) {
592 capture_buffer_.SplitIntoFrequencyBands();
593 render_buffer_.SplitIntoFrequencyBands();
594 }
595 }
596
597 static constexpr size_t kNumFramesToProcess = 20;
598 const int sample_rate_hz_;
599 const size_t num_bands_;
600 const size_t frame_length_;
601 const int fullband_frame_length_;
602 AudioBuffer capture_buffer_;
603 AudioBuffer render_buffer_;
604
605 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(EchoCanceller3Tester);
606};
607
608std::string ProduceDebugText(int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200609 rtc::StringBuilder ss;
peahd0263542017-01-03 04:20:34 -0800610 ss << "Sample rate: " << sample_rate_hz;
Jonas Olsson84df1c72018-09-14 16:59:32 +0200611 return ss.Release();
peahd0263542017-01-03 04:20:34 -0800612}
613
614std::string ProduceDebugText(int sample_rate_hz, int variant) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200615 rtc::StringBuilder ss;
peahd0263542017-01-03 04:20:34 -0800616 ss << "Sample rate: " << sample_rate_hz << ", variant: " << variant;
Jonas Olsson84df1c72018-09-14 16:59:32 +0200617 return ss.Release();
peahd0263542017-01-03 04:20:34 -0800618}
619
620} // namespace
621
622TEST(EchoCanceller3Buffering, CaptureBitexactness) {
Per Åhgrence202a02019-09-02 17:01:19 +0200623 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800624 SCOPED_TRACE(ProduceDebugText(rate));
625 EchoCanceller3Tester(rate).RunCaptureTransportVerificationTest();
626 }
627}
628
629TEST(EchoCanceller3Buffering, RenderBitexactness) {
Per Åhgrence202a02019-09-02 17:01:19 +0200630 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800631 SCOPED_TRACE(ProduceDebugText(rate));
632 EchoCanceller3Tester(rate).RunRenderTransportVerificationTest();
633 }
634}
635
Mirko Bonadeif0d9cda2019-01-17 20:43:58 +0000636TEST(EchoCanceller3Buffering, RenderSwapQueue) {
Per Åhgrence202a02019-09-02 17:01:19 +0200637 EchoCanceller3Tester(16000).RunRenderSwapQueueVerificationTest();
peahd0263542017-01-03 04:20:34 -0800638}
639
Mirko Bonadeif0d9cda2019-01-17 20:43:58 +0000640TEST(EchoCanceller3Buffering, RenderSwapQueueOverrunReturnValue) {
Per Åhgrence202a02019-09-02 17:01:19 +0200641 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800642 SCOPED_TRACE(ProduceDebugText(rate));
643 EchoCanceller3Tester(rate)
Mirko Bonadeif0d9cda2019-01-17 20:43:58 +0000644 .RunRenderPipelineSwapQueueOverrunReturnValueTest();
peahd0263542017-01-03 04:20:34 -0800645 }
646}
647
648TEST(EchoCanceller3Messaging, CaptureSaturation) {
649 auto variants = {EchoCanceller3Tester::SaturationTestVariant::kNone,
650 EchoCanceller3Tester::SaturationTestVariant::kOneNegative,
651 EchoCanceller3Tester::SaturationTestVariant::kOnePositive};
Per Åhgrence202a02019-09-02 17:01:19 +0200652 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800653 for (auto variant : variants) {
654 SCOPED_TRACE(ProduceDebugText(rate, static_cast<int>(variant)));
655 EchoCanceller3Tester(rate).RunCaptureSaturationVerificationTest(variant);
656 }
657 }
658}
659
660TEST(EchoCanceller3Messaging, EchoPathChange) {
661 auto variants = {
662 EchoCanceller3Tester::EchoPathChangeTestVariant::kNone,
663 EchoCanceller3Tester::EchoPathChangeTestVariant::kOneSticky,
664 EchoCanceller3Tester::EchoPathChangeTestVariant::kOneNonSticky};
Per Åhgrence202a02019-09-02 17:01:19 +0200665 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800666 for (auto variant : variants) {
667 SCOPED_TRACE(ProduceDebugText(rate, static_cast<int>(variant)));
668 EchoCanceller3Tester(rate).RunEchoPathChangeVerificationTest(variant);
669 }
670 }
671}
672
673TEST(EchoCanceller3Messaging, EchoLeakage) {
674 auto variants = {
675 EchoCanceller3Tester::EchoLeakageTestVariant::kNone,
676 EchoCanceller3Tester::EchoLeakageTestVariant::kFalseSticky,
677 EchoCanceller3Tester::EchoLeakageTestVariant::kTrueSticky,
678 EchoCanceller3Tester::EchoLeakageTestVariant::kTrueNonSticky};
Per Åhgrence202a02019-09-02 17:01:19 +0200679 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800680 for (auto variant : variants) {
681 SCOPED_TRACE(ProduceDebugText(rate, static_cast<int>(variant)));
682 EchoCanceller3Tester(rate).RunEchoLeakageVerificationTest(variant);
683 }
684 }
685}
686
687#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
peahd0263542017-01-03 04:20:34 -0800688
689TEST(EchoCanceller3InputCheck, WrongCaptureNumBandsCheckVerification) {
Per Åhgrence202a02019-09-02 17:01:19 +0200690 for (auto rate : {16000, 32000, 48000}) {
peahd0263542017-01-03 04:20:34 -0800691 SCOPED_TRACE(ProduceDebugText(rate));
692 EchoCanceller3Tester(rate).RunProcessCaptureNumBandsCheckVerification();
693 }
694}
695
peahd0263542017-01-03 04:20:34 -0800696// Verifiers that the verification for null input to the capture processing api
697// call works.
698TEST(EchoCanceller3InputCheck, NullCaptureProcessingParameter) {
Per Åhgrence202a02019-09-02 17:01:19 +0200699 EXPECT_DEATH(EchoCanceller3(EchoCanceller3Config(), 16000, 1, 1)
Gustaf Ullbergbd83b912017-10-18 12:32:42 +0200700 .ProcessCapture(nullptr, false),
701 "");
peahd0263542017-01-03 04:20:34 -0800702}
703
peah21920892017-02-08 05:08:56 -0800704// Verifies the check for correct sample rate.
peahcf02cf12017-04-05 14:18:07 -0700705// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
706// tests on test bots has been fixed.
707TEST(EchoCanceller3InputCheck, DISABLED_WrongSampleRate) {
peah21920892017-02-08 05:08:56 -0800708 ApmDataDumper data_dumper(0);
Per Åhgrence202a02019-09-02 17:01:19 +0200709 EXPECT_DEATH(EchoCanceller3(EchoCanceller3Config(), 8001, 1, 1), "");
peah21920892017-02-08 05:08:56 -0800710}
711
peahd0263542017-01-03 04:20:34 -0800712#endif
713
714} // namespace webrtc