1 /*
2 * Copyright (c) 2012 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 #include "modules/audio_processing/include/audio_processing.h"
11
12 #include <math.h>
13 #include <stdio.h>
14
15 #include <algorithm>
16 #include <cmath>
17 #include <limits>
18 #include <memory>
19 #include <numeric>
20 #include <queue>
21 #include <string>
22
23 #include "absl/flags/flag.h"
24 #include "absl/strings/string_view.h"
25 #include "api/audio/echo_detector_creator.h"
26 #include "api/make_ref_counted.h"
27 #include "common_audio/include/audio_util.h"
28 #include "common_audio/resampler/include/push_resampler.h"
29 #include "common_audio/resampler/push_sinc_resampler.h"
30 #include "common_audio/signal_processing/include/signal_processing_library.h"
31 #include "modules/audio_processing/aec_dump/aec_dump_factory.h"
32 #include "modules/audio_processing/audio_processing_impl.h"
33 #include "modules/audio_processing/include/mock_audio_processing.h"
34 #include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
35 #include "modules/audio_processing/test/protobuf_utils.h"
36 #include "modules/audio_processing/test/test_utils.h"
37 #include "rtc_base/arraysize.h"
38 #include "rtc_base/checks.h"
39 #include "rtc_base/fake_clock.h"
40 #include "rtc_base/gtest_prod_util.h"
41 #include "rtc_base/ignore_wundef.h"
42 #include "rtc_base/numerics/safe_conversions.h"
43 #include "rtc_base/numerics/safe_minmax.h"
44 #include "rtc_base/protobuf_utils.h"
45 #include "rtc_base/strings/string_builder.h"
46 #include "rtc_base/swap_queue.h"
47 #include "rtc_base/system/arch.h"
48 #include "rtc_base/task_queue_for_test.h"
49 #include "rtc_base/thread.h"
50 #include "system_wrappers/include/cpu_features_wrapper.h"
51 #include "test/gtest.h"
52 #include "test/testsupport/file_utils.h"
53
54 RTC_PUSH_IGNORING_WUNDEF()
55 #include "modules/audio_processing/debug.pb.h"
56 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
57 #include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
58 #else
59 #include "modules/audio_processing/test/unittest.pb.h"
60 #endif
61 RTC_POP_IGNORING_WUNDEF()
62
63 ABSL_FLAG(bool,
64 write_apm_ref_data,
65 false,
66 "Write ApmTest.Process results to file, instead of comparing results "
67 "to the existing reference data file.");
68
69 namespace webrtc {
70 namespace {
71
72 // All sample rates used by APM internally during processing. Other input /
73 // output rates are resampled to / from one of these.
74 const int kProcessSampleRates[] = {16000, 32000, 48000};
75
76 enum StreamDirection { kForward = 0, kReverse };
77
ConvertToFloat(const int16_t * int_data,ChannelBuffer<float> * cb)78 void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
79 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
80 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
81 cb_int.channels());
82 for (size_t i = 0; i < cb->num_channels(); ++i) {
83 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
84 }
85 }
86
ConvertToFloat(const Int16FrameData & frame,ChannelBuffer<float> * cb)87 void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
88 ConvertToFloat(frame.data.data(), cb);
89 }
90
MixStereoToMono(const float * stereo,float * mono,size_t samples_per_channel)91 void MixStereoToMono(const float* stereo,
92 float* mono,
93 size_t samples_per_channel) {
94 for (size_t i = 0; i < samples_per_channel; ++i)
95 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
96 }
97
MixStereoToMono(const int16_t * stereo,int16_t * mono,size_t samples_per_channel)98 void MixStereoToMono(const int16_t* stereo,
99 int16_t* mono,
100 size_t samples_per_channel) {
101 for (size_t i = 0; i < samples_per_channel; ++i)
102 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
103 }
104
CopyLeftToRightChannel(int16_t * stereo,size_t samples_per_channel)105 void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
106 for (size_t i = 0; i < samples_per_channel; i++) {
107 stereo[i * 2 + 1] = stereo[i * 2];
108 }
109 }
110
VerifyChannelsAreEqual(const int16_t * stereo,size_t samples_per_channel)111 void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
112 for (size_t i = 0; i < samples_per_channel; i++) {
113 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
114 }
115 }
116
SetFrameTo(Int16FrameData * frame,int16_t value)117 void SetFrameTo(Int16FrameData* frame, int16_t value) {
118 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
119 ++i) {
120 frame->data[i] = value;
121 }
122 }
123
SetFrameTo(Int16FrameData * frame,int16_t left,int16_t right)124 void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
125 ASSERT_EQ(2u, frame->num_channels);
126 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
127 frame->data[i] = left;
128 frame->data[i + 1] = right;
129 }
130 }
131
ScaleFrame(Int16FrameData * frame,float scale)132 void ScaleFrame(Int16FrameData* frame, float scale) {
133 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
134 ++i) {
135 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
136 }
137 }
138
FrameDataAreEqual(const Int16FrameData & frame1,const Int16FrameData & frame2)139 bool FrameDataAreEqual(const Int16FrameData& frame1,
140 const Int16FrameData& frame2) {
141 if (frame1.samples_per_channel != frame2.samples_per_channel) {
142 return false;
143 }
144 if (frame1.num_channels != frame2.num_channels) {
145 return false;
146 }
147 if (memcmp(
148 frame1.data.data(), frame2.data.data(),
149 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
150 return false;
151 }
152 return true;
153 }
154
GetMutableFrameData(Int16FrameData * frame)155 rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
156 int16_t* ptr = frame->data.data();
157 const size_t len = frame->samples_per_channel * frame->num_channels;
158 return rtc::ArrayView<int16_t>(ptr, len);
159 }
160
GetFrameData(const Int16FrameData & frame)161 rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
162 const int16_t* ptr = frame.data.data();
163 const size_t len = frame.samples_per_channel * frame.num_channels;
164 return rtc::ArrayView<const int16_t>(ptr, len);
165 }
166
EnableAllAPComponents(AudioProcessing * ap)167 void EnableAllAPComponents(AudioProcessing* ap) {
168 AudioProcessing::Config apm_config = ap->GetConfig();
169 apm_config.echo_canceller.enabled = true;
170 #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
171 apm_config.echo_canceller.mobile_mode = true;
172
173 apm_config.gain_controller1.enabled = true;
174 apm_config.gain_controller1.mode =
175 AudioProcessing::Config::GainController1::kAdaptiveDigital;
176 #elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
177 apm_config.echo_canceller.mobile_mode = false;
178
179 apm_config.gain_controller1.enabled = true;
180 apm_config.gain_controller1.mode =
181 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
182 #endif
183
184 apm_config.noise_suppression.enabled = true;
185
186 apm_config.high_pass_filter.enabled = true;
187 apm_config.pipeline.maximum_internal_processing_rate = 48000;
188 ap->ApplyConfig(apm_config);
189 }
190
191 // These functions are only used by ApmTest.Process.
192 template <class T>
AbsValue(T a)193 T AbsValue(T a) {
194 return a > 0 ? a : -a;
195 }
196
MaxAudioFrame(const Int16FrameData & frame)197 int16_t MaxAudioFrame(const Int16FrameData& frame) {
198 const size_t length = frame.samples_per_channel * frame.num_channels;
199 int16_t max_data = AbsValue(frame.data[0]);
200 for (size_t i = 1; i < length; i++) {
201 max_data = std::max(max_data, AbsValue(frame.data[i]));
202 }
203
204 return max_data;
205 }
206
OpenFileAndWriteMessage(absl::string_view filename,const MessageLite & msg)207 void OpenFileAndWriteMessage(absl::string_view filename,
208 const MessageLite& msg) {
209 FILE* file = fopen(std::string(filename).c_str(), "wb");
210 ASSERT_TRUE(file != NULL);
211
212 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
213 ASSERT_GT(size, 0);
214 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
215 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
216
217 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
218 ASSERT_EQ(static_cast<size_t>(size),
219 fwrite(array.get(), sizeof(array[0]), size, file));
220 fclose(file);
221 }
222
ResourceFilePath(absl::string_view name,int sample_rate_hz)223 std::string ResourceFilePath(absl::string_view name, int sample_rate_hz) {
224 rtc::StringBuilder ss;
225 // Resource files are all stereo.
226 ss << name << sample_rate_hz / 1000 << "_stereo";
227 return test::ResourcePath(ss.str(), "pcm");
228 }
229
230 // Temporary filenames unique to this process. Used to be able to run these
231 // tests in parallel as each process needs to be running in isolation they can't
232 // have competing filenames.
233 std::map<std::string, std::string> temp_filenames;
234
OutputFilePath(absl::string_view name,int input_rate,int output_rate,int reverse_input_rate,int reverse_output_rate,size_t num_input_channels,size_t num_output_channels,size_t num_reverse_input_channels,size_t num_reverse_output_channels,StreamDirection file_direction)235 std::string OutputFilePath(absl::string_view name,
236 int input_rate,
237 int output_rate,
238 int reverse_input_rate,
239 int reverse_output_rate,
240 size_t num_input_channels,
241 size_t num_output_channels,
242 size_t num_reverse_input_channels,
243 size_t num_reverse_output_channels,
244 StreamDirection file_direction) {
245 rtc::StringBuilder ss;
246 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
247 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
248 if (num_output_channels == 1) {
249 ss << "mono";
250 } else if (num_output_channels == 2) {
251 ss << "stereo";
252 } else {
253 RTC_DCHECK_NOTREACHED();
254 }
255 ss << output_rate / 1000;
256 if (num_reverse_output_channels == 1) {
257 ss << "_rmono";
258 } else if (num_reverse_output_channels == 2) {
259 ss << "_rstereo";
260 } else {
261 RTC_DCHECK_NOTREACHED();
262 }
263 ss << reverse_output_rate / 1000;
264 ss << "_d" << file_direction << "_pcm";
265
266 std::string filename = ss.str();
267 if (temp_filenames[filename].empty())
268 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
269 return temp_filenames[filename];
270 }
271
ClearTempFiles()272 void ClearTempFiles() {
273 for (auto& kv : temp_filenames)
274 remove(kv.second.c_str());
275 }
276
277 // Only remove "out" files. Keep "ref" files.
ClearTempOutFiles()278 void ClearTempOutFiles() {
279 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
280 const std::string& filename = it->first;
281 if (filename.substr(0, 3).compare("out") == 0) {
282 remove(it->second.c_str());
283 temp_filenames.erase(it++);
284 } else {
285 it++;
286 }
287 }
288 }
289
OpenFileAndReadMessage(absl::string_view filename,MessageLite * msg)290 void OpenFileAndReadMessage(absl::string_view filename, MessageLite* msg) {
291 FILE* file = fopen(std::string(filename).c_str(), "rb");
292 ASSERT_TRUE(file != NULL);
293 ReadMessageFromFile(file, msg);
294 fclose(file);
295 }
296
297 // Reads a 10 ms chunk (actually AudioProcessing::GetFrameSize() samples per
298 // channel) of int16 interleaved audio from the given (assumed stereo) file,
299 // converts to deinterleaved float (optionally downmixing) and returns the
300 // result in `cb`. Returns false if the file ended (or on error) and true
301 // otherwise.
302 //
303 // `int_data` and `float_data` are just temporary space that must be
304 // sufficiently large to hold the 10 ms chunk.
ReadChunk(FILE * file,int16_t * int_data,float * float_data,ChannelBuffer<float> * cb)305 bool ReadChunk(FILE* file,
306 int16_t* int_data,
307 float* float_data,
308 ChannelBuffer<float>* cb) {
309 // The files always contain stereo audio.
310 size_t frame_size = cb->num_frames() * 2;
311 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
312 if (read_count != frame_size) {
313 // Check that the file really ended.
314 RTC_DCHECK(feof(file));
315 return false; // This is expected.
316 }
317
318 S16ToFloat(int_data, frame_size, float_data);
319 if (cb->num_channels() == 1) {
320 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
321 } else {
322 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
323 }
324
325 return true;
326 }
327
328 // Returns the reference file name that matches the current CPU
329 // architecture/optimizations.
GetReferenceFilename()330 std::string GetReferenceFilename() {
331 #if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
332 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
333 #elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
334 if (GetCPUInfo(kAVX2) != 0) {
335 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
336 }
337 return test::ResourcePath("audio_processing/output_data_float", "pb");
338 #endif
339 }
340
341 // Flag that can temporarily be enabled for local debugging to inspect
342 // `ApmTest.VerifyDebugDump(Int|Float)` failures. Do not upload code changes
343 // with this flag set to true.
344 constexpr bool kDumpWhenExpectMessageEqFails = false;
345
346 // Checks the debug constants values used in this file so that no code change is
347 // submitted with values temporarily used for local debugging.
TEST(ApmUnitTests,CheckDebugConstants)348 TEST(ApmUnitTests, CheckDebugConstants) {
349 ASSERT_FALSE(kDumpWhenExpectMessageEqFails);
350 }
351
352 // Expects the equality of `actual` and `expected` by inspecting a hard-coded
353 // subset of `audioproc::Stream` fields.
ExpectStreamFieldsEq(const audioproc::Stream & actual,const audioproc::Stream & expected)354 void ExpectStreamFieldsEq(const audioproc::Stream& actual,
355 const audioproc::Stream& expected) {
356 EXPECT_EQ(actual.input_data(), expected.input_data());
357 EXPECT_EQ(actual.output_data(), expected.output_data());
358 EXPECT_EQ(actual.delay(), expected.delay());
359 EXPECT_EQ(actual.drift(), expected.drift());
360 EXPECT_EQ(actual.applied_input_volume(), expected.applied_input_volume());
361 EXPECT_EQ(actual.keypress(), expected.keypress());
362 }
363
364 // Expects the equality of `actual` and `expected` by inspecting a hard-coded
365 // subset of `audioproc::Event` fields.
ExpectEventFieldsEq(const audioproc::Event & actual,const audioproc::Event & expected)366 void ExpectEventFieldsEq(const audioproc::Event& actual,
367 const audioproc::Event& expected) {
368 EXPECT_EQ(actual.type(), expected.type());
369 if (actual.type() != expected.type()) {
370 return;
371 }
372 switch (actual.type()) {
373 case audioproc::Event::STREAM:
374 ExpectStreamFieldsEq(actual.stream(), expected.stream());
375 break;
376 default:
377 // Not implemented.
378 break;
379 }
380 }
381
382 // Returns true if the `actual` and `expected` byte streams share the same size
383 // and contain the same data. If they differ and `kDumpWhenExpectMessageEqFails`
384 // is true, checks the equality of a subset of `audioproc::Event` (nested)
385 // fields.
ExpectMessageEq(rtc::ArrayView<const uint8_t> actual,rtc::ArrayView<const uint8_t> expected)386 bool ExpectMessageEq(rtc::ArrayView<const uint8_t> actual,
387 rtc::ArrayView<const uint8_t> expected) {
388 EXPECT_EQ(actual.size(), expected.size());
389 if (actual.size() != expected.size()) {
390 return false;
391 }
392 if (memcmp(actual.data(), expected.data(), actual.size()) == 0) {
393 // Same message. No need to parse.
394 return true;
395 }
396 if (kDumpWhenExpectMessageEqFails) {
397 // Parse differing messages and expect equality to produce detailed error
398 // messages.
399 audioproc::Event event_actual, event_expected;
400 RTC_DCHECK(event_actual.ParseFromArray(actual.data(), actual.size()));
401 RTC_DCHECK(event_expected.ParseFromArray(expected.data(), expected.size()));
402 ExpectEventFieldsEq(event_actual, event_expected);
403 }
404 return false;
405 }
406
407 class ApmTest : public ::testing::Test {
408 protected:
409 ApmTest();
410 virtual void SetUp();
411 virtual void TearDown();
412
SetUpTestSuite()413 static void SetUpTestSuite() {}
414
TearDownTestSuite()415 static void TearDownTestSuite() { ClearTempFiles(); }
416
417 // Used to select between int and float interface tests.
418 enum Format { kIntFormat, kFloatFormat };
419
420 void Init(int sample_rate_hz,
421 int output_sample_rate_hz,
422 int reverse_sample_rate_hz,
423 size_t num_input_channels,
424 size_t num_output_channels,
425 size_t num_reverse_channels,
426 bool open_output_file);
427 void Init(AudioProcessing* ap);
428 void EnableAllComponents();
429 bool ReadFrame(FILE* file, Int16FrameData* frame);
430 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
431 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
432 void ReadFrameWithRewind(FILE* file,
433 Int16FrameData* frame,
434 ChannelBuffer<float>* cb);
435 void ProcessDelayVerificationTest(int delay_ms,
436 int system_delay_ms,
437 int delay_min,
438 int delay_max);
439 void TestChangingChannelsInt16Interface(
440 size_t num_channels,
441 AudioProcessing::Error expected_return);
442 void TestChangingForwardChannels(size_t num_in_channels,
443 size_t num_out_channels,
444 AudioProcessing::Error expected_return);
445 void TestChangingReverseChannels(size_t num_rev_channels,
446 AudioProcessing::Error expected_return);
447 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
448 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
449 void StreamParametersTest(Format format);
450 int ProcessStreamChooser(Format format);
451 int AnalyzeReverseStreamChooser(Format format);
452 void ProcessDebugDump(absl::string_view in_filename,
453 absl::string_view out_filename,
454 Format format,
455 int max_size_bytes);
456 void VerifyDebugDumpTest(Format format);
457
458 const std::string output_path_;
459 const std::string ref_filename_;
460 rtc::scoped_refptr<AudioProcessing> apm_;
461 Int16FrameData frame_;
462 Int16FrameData revframe_;
463 std::unique_ptr<ChannelBuffer<float>> float_cb_;
464 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
465 int output_sample_rate_hz_;
466 size_t num_output_channels_;
467 FILE* far_file_;
468 FILE* near_file_;
469 FILE* out_file_;
470 };
471
ApmTest()472 ApmTest::ApmTest()
473 : output_path_(test::OutputPath()),
474 ref_filename_(GetReferenceFilename()),
475 output_sample_rate_hz_(0),
476 num_output_channels_(0),
477 far_file_(NULL),
478 near_file_(NULL),
479 out_file_(NULL) {
480 apm_ = AudioProcessingBuilderForTesting().Create();
481 AudioProcessing::Config apm_config = apm_->GetConfig();
482 apm_config.gain_controller1.analog_gain_controller.enabled = false;
483 apm_config.pipeline.maximum_internal_processing_rate = 48000;
484 apm_->ApplyConfig(apm_config);
485 }
486
SetUp()487 void ApmTest::SetUp() {
488 ASSERT_TRUE(apm_.get() != NULL);
489
490 Init(32000, 32000, 32000, 2, 2, 2, false);
491 }
492
TearDown()493 void ApmTest::TearDown() {
494 if (far_file_) {
495 ASSERT_EQ(0, fclose(far_file_));
496 }
497 far_file_ = NULL;
498
499 if (near_file_) {
500 ASSERT_EQ(0, fclose(near_file_));
501 }
502 near_file_ = NULL;
503
504 if (out_file_) {
505 ASSERT_EQ(0, fclose(out_file_));
506 }
507 out_file_ = NULL;
508 }
509
Init(AudioProcessing * ap)510 void ApmTest::Init(AudioProcessing* ap) {
511 ASSERT_EQ(
512 kNoErr,
513 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
514 {output_sample_rate_hz_, num_output_channels_},
515 {revframe_.sample_rate_hz, revframe_.num_channels},
516 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
517 }
518
Init(int sample_rate_hz,int output_sample_rate_hz,int reverse_sample_rate_hz,size_t num_input_channels,size_t num_output_channels,size_t num_reverse_channels,bool open_output_file)519 void ApmTest::Init(int sample_rate_hz,
520 int output_sample_rate_hz,
521 int reverse_sample_rate_hz,
522 size_t num_input_channels,
523 size_t num_output_channels,
524 size_t num_reverse_channels,
525 bool open_output_file) {
526 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
527 output_sample_rate_hz_ = output_sample_rate_hz;
528 num_output_channels_ = num_output_channels;
529
530 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
531 &revfloat_cb_);
532 Init(apm_.get());
533
534 if (far_file_) {
535 ASSERT_EQ(0, fclose(far_file_));
536 }
537 std::string filename = ResourceFilePath("far", sample_rate_hz);
538 far_file_ = fopen(filename.c_str(), "rb");
539 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
540
541 if (near_file_) {
542 ASSERT_EQ(0, fclose(near_file_));
543 }
544 filename = ResourceFilePath("near", sample_rate_hz);
545 near_file_ = fopen(filename.c_str(), "rb");
546 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
547
548 if (open_output_file) {
549 if (out_file_) {
550 ASSERT_EQ(0, fclose(out_file_));
551 }
552 filename = OutputFilePath(
553 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
554 reverse_sample_rate_hz, num_input_channels, num_output_channels,
555 num_reverse_channels, num_reverse_channels, kForward);
556 out_file_ = fopen(filename.c_str(), "wb");
557 ASSERT_TRUE(out_file_ != NULL)
558 << "Could not open file " << filename << "\n";
559 }
560 }
561
EnableAllComponents()562 void ApmTest::EnableAllComponents() {
563 EnableAllAPComponents(apm_.get());
564 }
565
ReadFrame(FILE * file,Int16FrameData * frame,ChannelBuffer<float> * cb)566 bool ApmTest::ReadFrame(FILE* file,
567 Int16FrameData* frame,
568 ChannelBuffer<float>* cb) {
569 // The files always contain stereo audio.
570 size_t frame_size = frame->samples_per_channel * 2;
571 size_t read_count =
572 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
573 if (read_count != frame_size) {
574 // Check that the file really ended.
575 EXPECT_NE(0, feof(file));
576 return false; // This is expected.
577 }
578
579 if (frame->num_channels == 1) {
580 MixStereoToMono(frame->data.data(), frame->data.data(),
581 frame->samples_per_channel);
582 }
583
584 if (cb) {
585 ConvertToFloat(*frame, cb);
586 }
587 return true;
588 }
589
ReadFrame(FILE * file,Int16FrameData * frame)590 bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
591 return ReadFrame(file, frame, NULL);
592 }
593
594 // If the end of the file has been reached, rewind it and attempt to read the
595 // frame again.
ReadFrameWithRewind(FILE * file,Int16FrameData * frame,ChannelBuffer<float> * cb)596 void ApmTest::ReadFrameWithRewind(FILE* file,
597 Int16FrameData* frame,
598 ChannelBuffer<float>* cb) {
599 if (!ReadFrame(near_file_, &frame_, cb)) {
600 rewind(near_file_);
601 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
602 }
603 }
604
ReadFrameWithRewind(FILE * file,Int16FrameData * frame)605 void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
606 ReadFrameWithRewind(file, frame, NULL);
607 }
608
ProcessStreamChooser(Format format)609 int ApmTest::ProcessStreamChooser(Format format) {
610 if (format == kIntFormat) {
611 return apm_->ProcessStream(
612 frame_.data.data(),
613 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
614 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
615 frame_.data.data());
616 }
617 return apm_->ProcessStream(
618 float_cb_->channels(),
619 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
620 StreamConfig(output_sample_rate_hz_, num_output_channels_),
621 float_cb_->channels());
622 }
623
AnalyzeReverseStreamChooser(Format format)624 int ApmTest::AnalyzeReverseStreamChooser(Format format) {
625 if (format == kIntFormat) {
626 return apm_->ProcessReverseStream(
627 revframe_.data.data(),
628 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
629 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
630 revframe_.data.data());
631 }
632 return apm_->AnalyzeReverseStream(
633 revfloat_cb_->channels(),
634 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
635 }
636
ProcessDelayVerificationTest(int delay_ms,int system_delay_ms,int delay_min,int delay_max)637 void ApmTest::ProcessDelayVerificationTest(int delay_ms,
638 int system_delay_ms,
639 int delay_min,
640 int delay_max) {
641 // The `revframe_` and `frame_` should include the proper frame information,
642 // hence can be used for extracting information.
643 Int16FrameData tmp_frame;
644 std::queue<Int16FrameData*> frame_queue;
645 bool causal = true;
646
647 tmp_frame.CopyFrom(revframe_);
648 SetFrameTo(&tmp_frame, 0);
649
650 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
651 // Initialize the `frame_queue` with empty frames.
652 int frame_delay = delay_ms / 10;
653 while (frame_delay < 0) {
654 Int16FrameData* frame = new Int16FrameData();
655 frame->CopyFrom(tmp_frame);
656 frame_queue.push(frame);
657 frame_delay++;
658 causal = false;
659 }
660 while (frame_delay > 0) {
661 Int16FrameData* frame = new Int16FrameData();
662 frame->CopyFrom(tmp_frame);
663 frame_queue.push(frame);
664 frame_delay--;
665 }
666 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
667 // need enough frames with audio to have reliable estimates, but as few as
668 // possible to keep processing time down. 4.5 seconds seemed to be a good
669 // compromise for this recording.
670 for (int frame_count = 0; frame_count < 450; ++frame_count) {
671 Int16FrameData* frame = new Int16FrameData();
672 frame->CopyFrom(tmp_frame);
673 // Use the near end recording, since that has more speech in it.
674 ASSERT_TRUE(ReadFrame(near_file_, frame));
675 frame_queue.push(frame);
676 Int16FrameData* reverse_frame = frame;
677 Int16FrameData* process_frame = frame_queue.front();
678 if (!causal) {
679 reverse_frame = frame_queue.front();
680 // When we call ProcessStream() the frame is modified, so we can't use the
681 // pointer directly when things are non-causal. Use an intermediate frame
682 // and copy the data.
683 process_frame = &tmp_frame;
684 process_frame->CopyFrom(*frame);
685 }
686 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
687 reverse_frame->data.data(),
688 StreamConfig(reverse_frame->sample_rate_hz,
689 reverse_frame->num_channels),
690 StreamConfig(reverse_frame->sample_rate_hz,
691 reverse_frame->num_channels),
692 reverse_frame->data.data()));
693 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
694 EXPECT_EQ(apm_->kNoError,
695 apm_->ProcessStream(process_frame->data.data(),
696 StreamConfig(process_frame->sample_rate_hz,
697 process_frame->num_channels),
698 StreamConfig(process_frame->sample_rate_hz,
699 process_frame->num_channels),
700 process_frame->data.data()));
701 frame = frame_queue.front();
702 frame_queue.pop();
703 delete frame;
704
705 if (frame_count == 250) {
706 // Discard the first delay metrics to avoid convergence effects.
707 static_cast<void>(apm_->GetStatistics());
708 }
709 }
710
711 rewind(near_file_);
712 while (!frame_queue.empty()) {
713 Int16FrameData* frame = frame_queue.front();
714 frame_queue.pop();
715 delete frame;
716 }
717 // Calculate expected delay estimate and acceptable regions. Further,
718 // limit them w.r.t. AEC delay estimation support.
719 const size_t samples_per_ms =
720 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
721 const int expected_median =
722 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
723 const int expected_median_high = rtc::SafeClamp<int>(
724 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
725 delay_max);
726 const int expected_median_low = rtc::SafeClamp<int>(
727 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
728 delay_max);
729 // Verify delay metrics.
730 AudioProcessingStats stats = apm_->GetStatistics();
731 ASSERT_TRUE(stats.delay_median_ms.has_value());
732 int32_t median = *stats.delay_median_ms;
733 EXPECT_GE(expected_median_high, median);
734 EXPECT_LE(expected_median_low, median);
735 }
736
StreamParametersTest(Format format)737 void ApmTest::StreamParametersTest(Format format) {
738 // No errors when the components are disabled.
739 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
740
741 // -- Missing AGC level --
742 AudioProcessing::Config apm_config = apm_->GetConfig();
743 apm_config.gain_controller1.enabled = true;
744 apm_->ApplyConfig(apm_config);
745 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
746
747 // Resets after successful ProcessStream().
748 apm_->set_stream_analog_level(127);
749 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
750 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
751
752 // Other stream parameters set correctly.
753 apm_config.echo_canceller.enabled = true;
754 apm_config.echo_canceller.mobile_mode = false;
755 apm_->ApplyConfig(apm_config);
756 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
757 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
758 apm_config.gain_controller1.enabled = false;
759 apm_->ApplyConfig(apm_config);
760
761 // -- Missing delay --
762 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
763 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
764
765 // Resets after successful ProcessStream().
766 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
767 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
768 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
769
770 // Other stream parameters set correctly.
771 apm_config.gain_controller1.enabled = true;
772 apm_->ApplyConfig(apm_config);
773 apm_->set_stream_analog_level(127);
774 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
775 apm_config.gain_controller1.enabled = false;
776 apm_->ApplyConfig(apm_config);
777
778 // -- No stream parameters --
779 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
780 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
781
782 // -- All there --
783 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
784 apm_->set_stream_analog_level(127);
785 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
786 }
787
TEST_F(ApmTest,StreamParametersInt)788 TEST_F(ApmTest, StreamParametersInt) {
789 StreamParametersTest(kIntFormat);
790 }
791
TEST_F(ApmTest,StreamParametersFloat)792 TEST_F(ApmTest, StreamParametersFloat) {
793 StreamParametersTest(kFloatFormat);
794 }
795
TestChangingChannelsInt16Interface(size_t num_channels,AudioProcessing::Error expected_return)796 void ApmTest::TestChangingChannelsInt16Interface(
797 size_t num_channels,
798 AudioProcessing::Error expected_return) {
799 frame_.num_channels = num_channels;
800
801 EXPECT_EQ(expected_return,
802 apm_->ProcessStream(
803 frame_.data.data(),
804 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
805 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
806 frame_.data.data()));
807 EXPECT_EQ(expected_return,
808 apm_->ProcessReverseStream(
809 frame_.data.data(),
810 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
811 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
812 frame_.data.data()));
813 }
814
TestChangingForwardChannels(size_t num_in_channels,size_t num_out_channels,AudioProcessing::Error expected_return)815 void ApmTest::TestChangingForwardChannels(
816 size_t num_in_channels,
817 size_t num_out_channels,
818 AudioProcessing::Error expected_return) {
819 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
820 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
821
822 EXPECT_EQ(expected_return,
823 apm_->ProcessStream(float_cb_->channels(), input_stream,
824 output_stream, float_cb_->channels()));
825 }
826
TestChangingReverseChannels(size_t num_rev_channels,AudioProcessing::Error expected_return)827 void ApmTest::TestChangingReverseChannels(
828 size_t num_rev_channels,
829 AudioProcessing::Error expected_return) {
830 const ProcessingConfig processing_config = {
831 {{frame_.sample_rate_hz, apm_->num_input_channels()},
832 {output_sample_rate_hz_, apm_->num_output_channels()},
833 {frame_.sample_rate_hz, num_rev_channels},
834 {frame_.sample_rate_hz, num_rev_channels}}};
835
836 EXPECT_EQ(
837 expected_return,
838 apm_->ProcessReverseStream(
839 float_cb_->channels(), processing_config.reverse_input_stream(),
840 processing_config.reverse_output_stream(), float_cb_->channels()));
841 }
842
TEST_F(ApmTest,ChannelsInt16Interface)843 TEST_F(ApmTest, ChannelsInt16Interface) {
844 // Testing number of invalid and valid channels.
845 Init(16000, 16000, 16000, 4, 4, 4, false);
846
847 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
848
849 for (size_t i = 1; i < 4; i++) {
850 TestChangingChannelsInt16Interface(i, kNoErr);
851 EXPECT_EQ(i, apm_->num_input_channels());
852 }
853 }
854
TEST_F(ApmTest,Channels)855 TEST_F(ApmTest, Channels) {
856 // Testing number of invalid and valid channels.
857 Init(16000, 16000, 16000, 4, 4, 4, false);
858
859 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
860 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
861
862 for (size_t i = 1; i < 4; ++i) {
863 for (size_t j = 0; j < 1; ++j) {
864 // Output channels much be one or match input channels.
865 if (j == 1 || i == j) {
866 TestChangingForwardChannels(i, j, kNoErr);
867 TestChangingReverseChannels(i, kNoErr);
868
869 EXPECT_EQ(i, apm_->num_input_channels());
870 EXPECT_EQ(j, apm_->num_output_channels());
871 // The number of reverse channels used for processing to is always 1.
872 EXPECT_EQ(1u, apm_->num_reverse_channels());
873 } else {
874 TestChangingForwardChannels(i, j,
875 AudioProcessing::kBadNumberChannelsError);
876 }
877 }
878 }
879 }
880
TEST_F(ApmTest,SampleRatesInt)881 TEST_F(ApmTest, SampleRatesInt) {
882 // Testing some valid sample rates.
883 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
884 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
885 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
886 }
887 }
888
889 // This test repeatedly reconfigures the pre-amplifier in APM, processes a
890 // number of frames, and checks that output signal has the right level.
TEST_F(ApmTest,PreAmplifier)891 TEST_F(ApmTest, PreAmplifier) {
892 // Fill the audio frame with a sawtooth pattern.
893 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
894 const size_t samples_per_channel = frame_.samples_per_channel;
895 for (size_t i = 0; i < samples_per_channel; i++) {
896 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
897 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
898 }
899 }
900 // Cache the frame in tmp_frame.
901 Int16FrameData tmp_frame;
902 tmp_frame.CopyFrom(frame_);
903
904 auto compute_power = [](const Int16FrameData& frame) {
905 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
906 return std::accumulate(data.begin(), data.end(), 0.0f,
907 [](float a, float b) { return a + b * b; }) /
908 data.size() / 32768 / 32768;
909 };
910
911 const float input_power = compute_power(tmp_frame);
912 // Double-check that the input data is large compared to the error kEpsilon.
913 constexpr float kEpsilon = 1e-4f;
914 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
915
916 // 1. Enable pre-amp with 0 dB gain.
917 AudioProcessing::Config config = apm_->GetConfig();
918 config.pre_amplifier.enabled = true;
919 config.pre_amplifier.fixed_gain_factor = 1.0f;
920 apm_->ApplyConfig(config);
921
922 for (int i = 0; i < 20; ++i) {
923 frame_.CopyFrom(tmp_frame);
924 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
925 }
926 float output_power = compute_power(frame_);
927 EXPECT_NEAR(output_power, input_power, kEpsilon);
928 config = apm_->GetConfig();
929 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
930
931 // 2. Change pre-amp gain via ApplyConfig.
932 config.pre_amplifier.fixed_gain_factor = 2.0f;
933 apm_->ApplyConfig(config);
934
935 for (int i = 0; i < 20; ++i) {
936 frame_.CopyFrom(tmp_frame);
937 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
938 }
939 output_power = compute_power(frame_);
940 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
941 config = apm_->GetConfig();
942 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
943
944 // 3. Change pre-amp gain via a RuntimeSetting.
945 apm_->SetRuntimeSetting(
946 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
947
948 for (int i = 0; i < 20; ++i) {
949 frame_.CopyFrom(tmp_frame);
950 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
951 }
952 output_power = compute_power(frame_);
953 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
954 config = apm_->GetConfig();
955 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
956 }
957
958 // Ensures that the emulated analog mic gain functionality runs without
959 // crashing.
TEST_F(ApmTest,AnalogMicGainEmulation)960 TEST_F(ApmTest, AnalogMicGainEmulation) {
961 // Fill the audio frame with a sawtooth pattern.
962 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
963 const size_t samples_per_channel = frame_.samples_per_channel;
964 for (size_t i = 0; i < samples_per_channel; i++) {
965 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
966 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
967 }
968 }
969 // Cache the frame in tmp_frame.
970 Int16FrameData tmp_frame;
971 tmp_frame.CopyFrom(frame_);
972
973 // Enable the analog gain emulation.
974 AudioProcessing::Config config = apm_->GetConfig();
975 config.capture_level_adjustment.enabled = true;
976 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
977 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
978 config.gain_controller1.enabled = true;
979 config.gain_controller1.mode =
980 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
981 config.gain_controller1.analog_gain_controller.enabled = true;
982 apm_->ApplyConfig(config);
983
984 // Process a number of frames to ensure that the code runs without crashes.
985 for (int i = 0; i < 20; ++i) {
986 frame_.CopyFrom(tmp_frame);
987 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
988 }
989 }
990
991 // This test repeatedly reconfigures the capture level adjustment functionality
992 // in APM, processes a number of frames, and checks that output signal has the
993 // right level.
TEST_F(ApmTest,CaptureLevelAdjustment)994 TEST_F(ApmTest, CaptureLevelAdjustment) {
995 // Fill the audio frame with a sawtooth pattern.
996 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
997 const size_t samples_per_channel = frame_.samples_per_channel;
998 for (size_t i = 0; i < samples_per_channel; i++) {
999 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
1000 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
1001 }
1002 }
1003 // Cache the frame in tmp_frame.
1004 Int16FrameData tmp_frame;
1005 tmp_frame.CopyFrom(frame_);
1006
1007 auto compute_power = [](const Int16FrameData& frame) {
1008 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
1009 return std::accumulate(data.begin(), data.end(), 0.0f,
1010 [](float a, float b) { return a + b * b; }) /
1011 data.size() / 32768 / 32768;
1012 };
1013
1014 const float input_power = compute_power(tmp_frame);
1015 // Double-check that the input data is large compared to the error kEpsilon.
1016 constexpr float kEpsilon = 1e-20f;
1017 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
1018
1019 // 1. Enable pre-amp with 0 dB gain.
1020 AudioProcessing::Config config = apm_->GetConfig();
1021 config.capture_level_adjustment.enabled = true;
1022 config.capture_level_adjustment.pre_gain_factor = 0.5f;
1023 config.capture_level_adjustment.post_gain_factor = 4.f;
1024 const float expected_output_power1 =
1025 config.capture_level_adjustment.pre_gain_factor *
1026 config.capture_level_adjustment.pre_gain_factor *
1027 config.capture_level_adjustment.post_gain_factor *
1028 config.capture_level_adjustment.post_gain_factor * input_power;
1029 apm_->ApplyConfig(config);
1030
1031 for (int i = 0; i < 20; ++i) {
1032 frame_.CopyFrom(tmp_frame);
1033 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1034 }
1035 float output_power = compute_power(frame_);
1036 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
1037 config = apm_->GetConfig();
1038 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1039 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
1040
1041 // 2. Change pre-amp gain via ApplyConfig.
1042 config.capture_level_adjustment.pre_gain_factor = 1.0f;
1043 config.capture_level_adjustment.post_gain_factor = 2.f;
1044 const float expected_output_power2 =
1045 config.capture_level_adjustment.pre_gain_factor *
1046 config.capture_level_adjustment.pre_gain_factor *
1047 config.capture_level_adjustment.post_gain_factor *
1048 config.capture_level_adjustment.post_gain_factor * input_power;
1049 apm_->ApplyConfig(config);
1050
1051 for (int i = 0; i < 20; ++i) {
1052 frame_.CopyFrom(tmp_frame);
1053 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1054 }
1055 output_power = compute_power(frame_);
1056 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1057 config = apm_->GetConfig();
1058 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1059 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1060
1061 // 3. Change pre-amp gain via a RuntimeSetting.
1062 constexpr float kPreGain3 = 0.5f;
1063 constexpr float kPostGain3 = 3.f;
1064 const float expected_output_power3 =
1065 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1066
1067 apm_->SetRuntimeSetting(
1068 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1069 apm_->SetRuntimeSetting(
1070 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1071
1072 for (int i = 0; i < 20; ++i) {
1073 frame_.CopyFrom(tmp_frame);
1074 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1075 }
1076 output_power = compute_power(frame_);
1077 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1078 config = apm_->GetConfig();
1079 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1080 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1081 }
1082
TEST_F(ApmTest,GainControl)1083 TEST_F(ApmTest, GainControl) {
1084 AudioProcessing::Config config = apm_->GetConfig();
1085 config.gain_controller1.enabled = false;
1086 apm_->ApplyConfig(config);
1087 config.gain_controller1.enabled = true;
1088 apm_->ApplyConfig(config);
1089
1090 // Testing gain modes
1091 for (auto mode :
1092 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1093 AudioProcessing::Config::GainController1::kFixedDigital,
1094 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1095 config.gain_controller1.mode = mode;
1096 apm_->ApplyConfig(config);
1097 apm_->set_stream_analog_level(100);
1098 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1099 }
1100
1101 // Testing target levels
1102 for (int target_level_dbfs : {0, 15, 31}) {
1103 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1104 apm_->ApplyConfig(config);
1105 apm_->set_stream_analog_level(100);
1106 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1107 }
1108
1109 // Testing compression gains
1110 for (int compression_gain_db : {0, 10, 90}) {
1111 config.gain_controller1.compression_gain_db = compression_gain_db;
1112 apm_->ApplyConfig(config);
1113 apm_->set_stream_analog_level(100);
1114 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1115 }
1116
1117 // Testing limiter off/on
1118 for (bool enable : {false, true}) {
1119 config.gain_controller1.enable_limiter = enable;
1120 apm_->ApplyConfig(config);
1121 apm_->set_stream_analog_level(100);
1122 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1123 }
1124
1125 // Testing level limits.
1126 constexpr int kMinLevel = 0;
1127 constexpr int kMaxLevel = 255;
1128 apm_->set_stream_analog_level(kMinLevel);
1129 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1130 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1131 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1132 apm_->set_stream_analog_level(kMaxLevel);
1133 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1134 }
1135
1136 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
1137 using ApmDeathTest = ApmTest;
1138
TEST_F(ApmDeathTest,GainControlDiesOnTooLowTargetLevelDbfs)1139 TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
1140 auto config = apm_->GetConfig();
1141 config.gain_controller1.enabled = true;
1142 config.gain_controller1.target_level_dbfs = -1;
1143 EXPECT_DEATH(apm_->ApplyConfig(config), "");
1144 }
1145
TEST_F(ApmDeathTest,GainControlDiesOnTooHighTargetLevelDbfs)1146 TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
1147 auto config = apm_->GetConfig();
1148 config.gain_controller1.enabled = true;
1149 config.gain_controller1.target_level_dbfs = 32;
1150 EXPECT_DEATH(apm_->ApplyConfig(config), "");
1151 }
1152
TEST_F(ApmDeathTest,GainControlDiesOnTooLowCompressionGainDb)1153 TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
1154 auto config = apm_->GetConfig();
1155 config.gain_controller1.enabled = true;
1156 config.gain_controller1.compression_gain_db = -1;
1157 EXPECT_DEATH(apm_->ApplyConfig(config), "");
1158 }
1159
TEST_F(ApmDeathTest,GainControlDiesOnTooHighCompressionGainDb)1160 TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
1161 auto config = apm_->GetConfig();
1162 config.gain_controller1.enabled = true;
1163 config.gain_controller1.compression_gain_db = 91;
1164 EXPECT_DEATH(apm_->ApplyConfig(config), "");
1165 }
1166
TEST_F(ApmDeathTest,ApmDiesOnTooLowAnalogLevel)1167 TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
1168 auto config = apm_->GetConfig();
1169 config.gain_controller1.enabled = true;
1170 apm_->ApplyConfig(config);
1171 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
1172 }
1173
TEST_F(ApmDeathTest,ApmDiesOnTooHighAnalogLevel)1174 TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
1175 auto config = apm_->GetConfig();
1176 config.gain_controller1.enabled = true;
1177 apm_->ApplyConfig(config);
1178 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
1179 }
1180 #endif
1181
RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate)1182 void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
1183 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
1184 auto config = apm_->GetConfig();
1185 config.gain_controller1.enabled = true;
1186 config.gain_controller1.mode =
1187 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1188 apm_->ApplyConfig(config);
1189
1190 int out_analog_level = 0;
1191 for (int i = 0; i < 2000; ++i) {
1192 ReadFrameWithRewind(near_file_, &frame_);
1193 // Ensure the audio is at a low level, so the AGC will try to increase it.
1194 ScaleFrame(&frame_, 0.25);
1195
1196 // Always pass in the same volume.
1197 apm_->set_stream_analog_level(100);
1198 EXPECT_EQ(apm_->kNoError,
1199 apm_->ProcessStream(
1200 frame_.data.data(),
1201 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1202 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1203 frame_.data.data()));
1204 out_analog_level = apm_->recommended_stream_analog_level();
1205 }
1206
1207 // Ensure the AGC is still able to reach the maximum.
1208 EXPECT_EQ(255, out_analog_level);
1209 }
1210
1211 // Verifies that despite volume slider quantization, the AGC can continue to
1212 // increase its volume.
TEST_F(ApmTest,QuantizedVolumeDoesNotGetStuck)1213 TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
1214 for (size_t sample_rate_hz : kProcessSampleRates) {
1215 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1216 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz);
1217 }
1218 }
1219
RunManualVolumeChangeIsPossibleTest(int sample_rate)1220 void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
1221 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
1222 auto config = apm_->GetConfig();
1223 config.gain_controller1.enabled = true;
1224 config.gain_controller1.mode =
1225 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1226 apm_->ApplyConfig(config);
1227
1228 int out_analog_level = 100;
1229 for (int i = 0; i < 1000; ++i) {
1230 ReadFrameWithRewind(near_file_, &frame_);
1231 // Ensure the audio is at a low level, so the AGC will try to increase it.
1232 ScaleFrame(&frame_, 0.25);
1233
1234 apm_->set_stream_analog_level(out_analog_level);
1235 EXPECT_EQ(apm_->kNoError,
1236 apm_->ProcessStream(
1237 frame_.data.data(),
1238 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1239 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1240 frame_.data.data()));
1241 out_analog_level = apm_->recommended_stream_analog_level();
1242 }
1243
1244 // Ensure the volume was raised.
1245 EXPECT_GT(out_analog_level, 100);
1246 int highest_level_reached = out_analog_level;
1247 // Simulate a user manual volume change.
1248 out_analog_level = 100;
1249
1250 for (int i = 0; i < 300; ++i) {
1251 ReadFrameWithRewind(near_file_, &frame_);
1252 ScaleFrame(&frame_, 0.25);
1253
1254 apm_->set_stream_analog_level(out_analog_level);
1255 EXPECT_EQ(apm_->kNoError,
1256 apm_->ProcessStream(
1257 frame_.data.data(),
1258 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1259 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1260 frame_.data.data()));
1261 out_analog_level = apm_->recommended_stream_analog_level();
1262 // Check that AGC respected the manually adjusted volume.
1263 EXPECT_LT(out_analog_level, highest_level_reached);
1264 }
1265 // Check that the volume was still raised.
1266 EXPECT_GT(out_analog_level, 100);
1267 }
1268
TEST_F(ApmTest,ManualVolumeChangeIsPossible)1269 TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
1270 for (size_t sample_rate_hz : kProcessSampleRates) {
1271 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1272 RunManualVolumeChangeIsPossibleTest(sample_rate_hz);
1273 }
1274 }
1275
TEST_F(ApmTest,HighPassFilter)1276 TEST_F(ApmTest, HighPassFilter) {
1277 // Turn HP filter on/off
1278 AudioProcessing::Config apm_config;
1279 apm_config.high_pass_filter.enabled = true;
1280 apm_->ApplyConfig(apm_config);
1281 apm_config.high_pass_filter.enabled = false;
1282 apm_->ApplyConfig(apm_config);
1283 }
1284
TEST_F(ApmTest,AllProcessingDisabledByDefault)1285 TEST_F(ApmTest, AllProcessingDisabledByDefault) {
1286 AudioProcessing::Config config = apm_->GetConfig();
1287 EXPECT_FALSE(config.echo_canceller.enabled);
1288 EXPECT_FALSE(config.high_pass_filter.enabled);
1289 EXPECT_FALSE(config.gain_controller1.enabled);
1290 EXPECT_FALSE(config.noise_suppression.enabled);
1291 }
1292
TEST_F(ApmTest,NoProcessingWhenAllComponentsDisabledInt)1293 TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledInt) {
1294 // Test that ProcessStream simply copies input to output when all components
1295 // are disabled.
1296 // Runs over all processing rates, and some particularly common or special
1297 // rates.
1298 // - 8000 Hz: lowest sample rate seen in Chrome metrics,
1299 // - 22050 Hz: APM input/output frames are not exactly 10 ms,
1300 // - 44100 Hz: very common desktop sample rate.
1301 constexpr int kSampleRatesHz[] = {8000, 16000, 22050, 32000, 44100, 48000};
1302 for (size_t sample_rate_hz : kSampleRatesHz) {
1303 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1304 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false);
1305 SetFrameTo(&frame_, 1000, 2000);
1306 Int16FrameData frame_copy;
1307 frame_copy.CopyFrom(frame_);
1308 for (int j = 0; j < 1000; j++) {
1309 EXPECT_EQ(apm_->kNoError,
1310 apm_->ProcessStream(
1311 frame_.data.data(),
1312 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1313 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1314 frame_.data.data()));
1315 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1316 EXPECT_EQ(apm_->kNoError,
1317 apm_->ProcessReverseStream(
1318 frame_.data.data(),
1319 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1320 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1321 frame_.data.data()));
1322 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1323 }
1324 }
1325 }
1326
TEST_F(ApmTest,NoProcessingWhenAllComponentsDisabledFloat)1327 TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1328 // Test that ProcessStream simply copies input to output when all components
1329 // are disabled.
1330 const size_t kSamples = 160;
1331 const int sample_rate = 16000;
1332 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
1333 float dest[kSamples] = {};
1334
1335 auto src_channels = &src[0];
1336 auto dest_channels = &dest[0];
1337
1338 apm_ = AudioProcessingBuilderForTesting().Create();
1339 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1340 StreamConfig(sample_rate, 1),
1341 &dest_channels));
1342
1343 for (size_t i = 0; i < kSamples; ++i) {
1344 EXPECT_EQ(src[i], dest[i]);
1345 }
1346
1347 // Same for ProcessReverseStream.
1348 float rev_dest[kSamples] = {};
1349 auto rev_dest_channels = &rev_dest[0];
1350
1351 StreamConfig input_stream = {sample_rate, 1};
1352 StreamConfig output_stream = {sample_rate, 1};
1353 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1354 output_stream, &rev_dest_channels));
1355
1356 for (size_t i = 0; i < kSamples; ++i) {
1357 EXPECT_EQ(src[i], rev_dest[i]);
1358 }
1359 }
1360
TEST_F(ApmTest,IdenticalInputChannelsResultInIdenticalOutputChannels)1361 TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1362 EnableAllComponents();
1363
1364 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
1365 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1366 2, 2, 2, false);
1367 int analog_level = 127;
1368 ASSERT_EQ(0, feof(far_file_));
1369 ASSERT_EQ(0, feof(near_file_));
1370 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
1371 CopyLeftToRightChannel(revframe_.data.data(),
1372 revframe_.samples_per_channel);
1373
1374 ASSERT_EQ(
1375 kNoErr,
1376 apm_->ProcessReverseStream(
1377 revframe_.data.data(),
1378 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1379 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1380 revframe_.data.data()));
1381
1382 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
1383
1384 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
1385 apm_->set_stream_analog_level(analog_level);
1386 ASSERT_EQ(kNoErr,
1387 apm_->ProcessStream(
1388 frame_.data.data(),
1389 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1390 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1391 frame_.data.data()));
1392 analog_level = apm_->recommended_stream_analog_level();
1393
1394 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
1395 }
1396 rewind(far_file_);
1397 rewind(near_file_);
1398 }
1399 }
1400
TEST_F(ApmTest,SplittingFilter)1401 TEST_F(ApmTest, SplittingFilter) {
1402 // Verify the filter is not active through undistorted audio when:
1403 // 1. No components are enabled...
1404 SetFrameTo(&frame_, 1000);
1405 Int16FrameData frame_copy;
1406 frame_copy.CopyFrom(frame_);
1407 EXPECT_EQ(apm_->kNoError,
1408 apm_->ProcessStream(
1409 frame_.data.data(),
1410 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1411 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1412 frame_.data.data()));
1413 EXPECT_EQ(apm_->kNoError,
1414 apm_->ProcessStream(
1415 frame_.data.data(),
1416 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1417 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1418 frame_.data.data()));
1419 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1420
1421 // 2. Only the level estimator is enabled...
1422 auto apm_config = apm_->GetConfig();
1423 SetFrameTo(&frame_, 1000);
1424 frame_copy.CopyFrom(frame_);
1425 apm_->ApplyConfig(apm_config);
1426 EXPECT_EQ(apm_->kNoError,
1427 apm_->ProcessStream(
1428 frame_.data.data(),
1429 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1430 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1431 frame_.data.data()));
1432 EXPECT_EQ(apm_->kNoError,
1433 apm_->ProcessStream(
1434 frame_.data.data(),
1435 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1436 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1437 frame_.data.data()));
1438 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1439 apm_->ApplyConfig(apm_config);
1440
1441 // Check the test is valid. We should have distortion from the filter
1442 // when AEC is enabled (which won't affect the audio).
1443 apm_config.echo_canceller.enabled = true;
1444 apm_config.echo_canceller.mobile_mode = false;
1445 apm_->ApplyConfig(apm_config);
1446 frame_.samples_per_channel = 320;
1447 frame_.num_channels = 2;
1448 frame_.sample_rate_hz = 32000;
1449 SetFrameTo(&frame_, 1000);
1450 frame_copy.CopyFrom(frame_);
1451 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
1452 EXPECT_EQ(apm_->kNoError,
1453 apm_->ProcessStream(
1454 frame_.data.data(),
1455 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1456 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1457 frame_.data.data()));
1458 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
1459 }
1460
1461 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
ProcessDebugDump(absl::string_view in_filename,absl::string_view out_filename,Format format,int max_size_bytes)1462 void ApmTest::ProcessDebugDump(absl::string_view in_filename,
1463 absl::string_view out_filename,
1464 Format format,
1465 int max_size_bytes) {
1466 TaskQueueForTest worker_queue("ApmTest_worker_queue");
1467 FILE* in_file = fopen(std::string(in_filename).c_str(), "rb");
1468 ASSERT_TRUE(in_file != NULL);
1469 audioproc::Event event_msg;
1470 bool first_init = true;
1471
1472 while (ReadMessageFromFile(in_file, &event_msg)) {
1473 if (event_msg.type() == audioproc::Event::INIT) {
1474 const audioproc::Init msg = event_msg.init();
1475 int reverse_sample_rate = msg.sample_rate();
1476 if (msg.has_reverse_sample_rate()) {
1477 reverse_sample_rate = msg.reverse_sample_rate();
1478 }
1479 int output_sample_rate = msg.sample_rate();
1480 if (msg.has_output_sample_rate()) {
1481 output_sample_rate = msg.output_sample_rate();
1482 }
1483
1484 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1485 msg.num_input_channels(), msg.num_output_channels(),
1486 msg.num_reverse_channels(), false);
1487 if (first_init) {
1488 // AttachAecDump() writes an additional init message. Don't start
1489 // recording until after the first init to avoid the extra message.
1490 auto aec_dump =
1491 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1492 EXPECT_TRUE(aec_dump);
1493 apm_->AttachAecDump(std::move(aec_dump));
1494 first_init = false;
1495 }
1496
1497 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1498 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1499
1500 if (msg.channel_size() > 0) {
1501 ASSERT_EQ(revframe_.num_channels,
1502 static_cast<size_t>(msg.channel_size()));
1503 for (int i = 0; i < msg.channel_size(); ++i) {
1504 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1505 msg.channel(i).size());
1506 }
1507 } else {
1508 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
1509 if (format == kFloatFormat) {
1510 // We're using an int16 input file; convert to float.
1511 ConvertToFloat(revframe_, revfloat_cb_.get());
1512 }
1513 }
1514 AnalyzeReverseStreamChooser(format);
1515
1516 } else if (event_msg.type() == audioproc::Event::STREAM) {
1517 const audioproc::Stream msg = event_msg.stream();
1518 // ProcessStream could have changed this for the output frame.
1519 frame_.num_channels = apm_->num_input_channels();
1520
1521 apm_->set_stream_analog_level(msg.applied_input_volume());
1522 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
1523 if (msg.has_keypress()) {
1524 apm_->set_stream_key_pressed(msg.keypress());
1525 } else {
1526 apm_->set_stream_key_pressed(true);
1527 }
1528
1529 if (msg.input_channel_size() > 0) {
1530 ASSERT_EQ(frame_.num_channels,
1531 static_cast<size_t>(msg.input_channel_size()));
1532 for (int i = 0; i < msg.input_channel_size(); ++i) {
1533 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1534 msg.input_channel(i).size());
1535 }
1536 } else {
1537 memcpy(frame_.data.data(), msg.input_data().data(),
1538 msg.input_data().size());
1539 if (format == kFloatFormat) {
1540 // We're using an int16 input file; convert to float.
1541 ConvertToFloat(frame_, float_cb_.get());
1542 }
1543 }
1544 ProcessStreamChooser(format);
1545 }
1546 }
1547 apm_->DetachAecDump();
1548 fclose(in_file);
1549 }
1550
VerifyDebugDumpTest(Format format)1551 void ApmTest::VerifyDebugDumpTest(Format format) {
1552 rtc::ScopedFakeClock fake_clock;
1553 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
1554 std::string format_string;
1555 switch (format) {
1556 case kIntFormat:
1557 format_string = "_int";
1558 break;
1559 case kFloatFormat:
1560 format_string = "_float";
1561 break;
1562 }
1563 const std::string ref_filename = test::TempFilename(
1564 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1565 const std::string out_filename = test::TempFilename(
1566 test::OutputPath(), std::string("out") + format_string + "_aecdump");
1567 const std::string limited_filename = test::TempFilename(
1568 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1569 const size_t logging_limit_bytes = 100000;
1570 // We expect at least this many bytes in the created logfile.
1571 const size_t logging_expected_bytes = 95000;
1572 EnableAllComponents();
1573 ProcessDebugDump(in_filename, ref_filename, format, -1);
1574 ProcessDebugDump(ref_filename, out_filename, format, -1);
1575 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
1576
1577 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1578 FILE* out_file = fopen(out_filename.c_str(), "rb");
1579 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
1580 ASSERT_TRUE(ref_file != NULL);
1581 ASSERT_TRUE(out_file != NULL);
1582 ASSERT_TRUE(limited_file != NULL);
1583 std::unique_ptr<uint8_t[]> ref_bytes;
1584 std::unique_ptr<uint8_t[]> out_bytes;
1585 std::unique_ptr<uint8_t[]> limited_bytes;
1586
1587 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1588 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
1589 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
1590 size_t bytes_read = 0;
1591 size_t bytes_read_limited = 0;
1592 while (ref_size > 0 && out_size > 0) {
1593 bytes_read += ref_size;
1594 bytes_read_limited += limited_size;
1595 EXPECT_EQ(ref_size, out_size);
1596 EXPECT_GE(ref_size, limited_size);
1597 EXPECT_TRUE(ExpectMessageEq(/*actual=*/{out_bytes.get(), out_size},
1598 /*expected=*/{ref_bytes.get(), ref_size}));
1599 if (limited_size > 0) {
1600 EXPECT_TRUE(
1601 ExpectMessageEq(/*actual=*/{limited_bytes.get(), limited_size},
1602 /*expected=*/{ref_bytes.get(), ref_size}));
1603 }
1604 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1605 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
1606 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
1607 }
1608 EXPECT_GT(bytes_read, 0u);
1609 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1610 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
1611 EXPECT_NE(0, feof(ref_file));
1612 EXPECT_NE(0, feof(out_file));
1613 EXPECT_NE(0, feof(limited_file));
1614 ASSERT_EQ(0, fclose(ref_file));
1615 ASSERT_EQ(0, fclose(out_file));
1616 ASSERT_EQ(0, fclose(limited_file));
1617 remove(ref_filename.c_str());
1618 remove(out_filename.c_str());
1619 remove(limited_filename.c_str());
1620 }
1621
TEST_F(ApmTest,VerifyDebugDumpInt)1622 TEST_F(ApmTest, VerifyDebugDumpInt) {
1623 VerifyDebugDumpTest(kIntFormat);
1624 }
1625
TEST_F(ApmTest,VerifyDebugDumpFloat)1626 TEST_F(ApmTest, VerifyDebugDumpFloat) {
1627 VerifyDebugDumpTest(kFloatFormat);
1628 }
1629 #endif
1630
1631 // TODO(andrew): expand test to verify output.
TEST_F(ApmTest,DebugDump)1632 TEST_F(ApmTest, DebugDump) {
1633 TaskQueueForTest worker_queue("ApmTest_worker_queue");
1634 const std::string filename =
1635 test::TempFilename(test::OutputPath(), "debug_aec");
1636 {
1637 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1638 EXPECT_FALSE(aec_dump);
1639 }
1640
1641 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1642 // Stopping without having started should be OK.
1643 apm_->DetachAecDump();
1644
1645 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1646 EXPECT_TRUE(aec_dump);
1647 apm_->AttachAecDump(std::move(aec_dump));
1648 EXPECT_EQ(apm_->kNoError,
1649 apm_->ProcessStream(
1650 frame_.data.data(),
1651 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1652 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1653 frame_.data.data()));
1654 EXPECT_EQ(apm_->kNoError,
1655 apm_->ProcessReverseStream(
1656 revframe_.data.data(),
1657 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1658 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1659 revframe_.data.data()));
1660 apm_->DetachAecDump();
1661
1662 // Verify the file has been written.
1663 FILE* fid = fopen(filename.c_str(), "r");
1664 ASSERT_TRUE(fid != NULL);
1665
1666 // Clean it up.
1667 ASSERT_EQ(0, fclose(fid));
1668 ASSERT_EQ(0, remove(filename.c_str()));
1669 #else
1670 // Verify the file has NOT been written.
1671 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1672 #endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1673 }
1674
1675 // TODO(andrew): expand test to verify output.
TEST_F(ApmTest,DebugDumpFromFileHandle)1676 TEST_F(ApmTest, DebugDumpFromFileHandle) {
1677 TaskQueueForTest worker_queue("ApmTest_worker_queue");
1678
1679 const std::string filename =
1680 test::TempFilename(test::OutputPath(), "debug_aec");
1681 FileWrapper f = FileWrapper::OpenWriteOnly(filename);
1682 ASSERT_TRUE(f.is_open());
1683
1684 #ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1685 // Stopping without having started should be OK.
1686 apm_->DetachAecDump();
1687
1688 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
1689 EXPECT_TRUE(aec_dump);
1690 apm_->AttachAecDump(std::move(aec_dump));
1691 EXPECT_EQ(apm_->kNoError,
1692 apm_->ProcessReverseStream(
1693 revframe_.data.data(),
1694 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1695 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1696 revframe_.data.data()));
1697 EXPECT_EQ(apm_->kNoError,
1698 apm_->ProcessStream(
1699 frame_.data.data(),
1700 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1701 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1702 frame_.data.data()));
1703 apm_->DetachAecDump();
1704
1705 // Verify the file has been written.
1706 FILE* fid = fopen(filename.c_str(), "r");
1707 ASSERT_TRUE(fid != NULL);
1708
1709 // Clean it up.
1710 ASSERT_EQ(0, fclose(fid));
1711 ASSERT_EQ(0, remove(filename.c_str()));
1712 #endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1713 }
1714
1715 // TODO(andrew): Add a test to process a few frames with different combinations
1716 // of enabled components.
1717
TEST_F(ApmTest,Process)1718 TEST_F(ApmTest, Process) {
1719 GOOGLE_PROTOBUF_VERIFY_VERSION;
1720 audioproc::OutputData ref_data;
1721
1722 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
1723 OpenFileAndReadMessage(ref_filename_, &ref_data);
1724 } else {
1725 const int kChannels[] = {1, 2};
1726 // Write the desired tests to the protobuf reference file.
1727 for (size_t i = 0; i < arraysize(kChannels); i++) {
1728 for (size_t j = 0; j < arraysize(kChannels); j++) {
1729 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) {
1730 audioproc::Test* test = ref_data.add_test();
1731 test->set_num_reverse_channels(kChannels[i]);
1732 test->set_num_input_channels(kChannels[j]);
1733 test->set_num_output_channels(kChannels[j]);
1734 test->set_sample_rate(sample_rate_hz);
1735 test->set_use_aec_extended_filter(false);
1736 }
1737 }
1738 }
1739 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1740 // To test the extended filter mode.
1741 audioproc::Test* test = ref_data.add_test();
1742 test->set_num_reverse_channels(2);
1743 test->set_num_input_channels(2);
1744 test->set_num_output_channels(2);
1745 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1746 test->set_use_aec_extended_filter(true);
1747 #endif
1748 }
1749
1750 for (int i = 0; i < ref_data.test_size(); i++) {
1751 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
1752
1753 audioproc::Test* test = ref_data.mutable_test(i);
1754 // TODO(ajm): We no longer allow different input and output channels. Skip
1755 // these tests for now, but they should be removed from the set.
1756 if (test->num_input_channels() != test->num_output_channels())
1757 continue;
1758
1759 apm_ = AudioProcessingBuilderForTesting()
1760 .SetEchoDetector(CreateEchoDetector())
1761 .Create();
1762 AudioProcessing::Config apm_config = apm_->GetConfig();
1763 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1764 apm_->ApplyConfig(apm_config);
1765
1766 EnableAllComponents();
1767
1768 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
1769 static_cast<size_t>(test->num_input_channels()),
1770 static_cast<size_t>(test->num_output_channels()),
1771 static_cast<size_t>(test->num_reverse_channels()), true);
1772
1773 int frame_count = 0;
1774 int analog_level = 127;
1775 int analog_level_average = 0;
1776 int max_output_average = 0;
1777 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1778 int stats_index = 0;
1779 #endif
1780
1781 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
1782 EXPECT_EQ(
1783 apm_->kNoError,
1784 apm_->ProcessReverseStream(
1785 revframe_.data.data(),
1786 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1787 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1788 revframe_.data.data()));
1789
1790 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
1791 apm_->set_stream_analog_level(analog_level);
1792
1793 EXPECT_EQ(apm_->kNoError,
1794 apm_->ProcessStream(
1795 frame_.data.data(),
1796 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1797 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1798 frame_.data.data()));
1799
1800 // Ensure the frame was downmixed properly.
1801 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
1802 frame_.num_channels);
1803
1804 max_output_average += MaxAudioFrame(frame_);
1805
1806 analog_level = apm_->recommended_stream_analog_level();
1807 analog_level_average += analog_level;
1808 AudioProcessingStats stats = apm_->GetStatistics();
1809
1810 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
1811 size_t write_count =
1812 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
1813 ASSERT_EQ(frame_size, write_count);
1814
1815 // Reset in case of downmixing.
1816 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
1817 frame_count++;
1818
1819 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1820 const int kStatsAggregationFrameNum = 100; // 1 second.
1821 if (frame_count % kStatsAggregationFrameNum == 0) {
1822 // Get echo and delay metrics.
1823 AudioProcessingStats stats2 = apm_->GetStatistics();
1824
1825 // Echo metrics.
1826 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
1827 const float echo_return_loss_enhancement =
1828 stats2.echo_return_loss_enhancement.value_or(-1.0f);
1829 const float residual_echo_likelihood =
1830 stats2.residual_echo_likelihood.value_or(-1.0f);
1831 const float residual_echo_likelihood_recent_max =
1832 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
1833
1834 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
1835 const audioproc::Test::EchoMetrics& reference =
1836 test->echo_metrics(stats_index);
1837 constexpr float kEpsilon = 0.01;
1838 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1839 EXPECT_NEAR(echo_return_loss_enhancement,
1840 reference.echo_return_loss_enhancement(), kEpsilon);
1841 EXPECT_NEAR(residual_echo_likelihood,
1842 reference.residual_echo_likelihood(), kEpsilon);
1843 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1844 reference.residual_echo_likelihood_recent_max(),
1845 kEpsilon);
1846 ++stats_index;
1847 } else {
1848 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1849 message_echo->set_echo_return_loss(echo_return_loss);
1850 message_echo->set_echo_return_loss_enhancement(
1851 echo_return_loss_enhancement);
1852 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1853 message_echo->set_residual_echo_likelihood_recent_max(
1854 residual_echo_likelihood_recent_max);
1855 }
1856 }
1857 #endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
1858 }
1859 max_output_average /= frame_count;
1860 analog_level_average /= frame_count;
1861
1862 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
1863 const int kIntNear = 1;
1864 // All numbers being consistently higher on N7 compare to the reference
1865 // data.
1866 // TODO(bjornv): If we start getting more of these offsets on Android we
1867 // should consider a different approach. Either using one slack for all,
1868 // or generate a separate android reference.
1869 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
1870 const int kMaxOutputAverageOffset = 9;
1871 const int kMaxOutputAverageNear = 26;
1872 #else
1873 const int kMaxOutputAverageOffset = 0;
1874 const int kMaxOutputAverageNear = kIntNear;
1875 #endif
1876 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
1877 EXPECT_NEAR(test->max_output_average(),
1878 max_output_average - kMaxOutputAverageOffset,
1879 kMaxOutputAverageNear);
1880 } else {
1881 test->set_analog_level_average(analog_level_average);
1882 test->set_max_output_average(max_output_average);
1883 }
1884
1885 rewind(far_file_);
1886 rewind(near_file_);
1887 }
1888
1889 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
1890 OpenFileAndWriteMessage(ref_filename_, ref_data);
1891 }
1892 }
1893
1894 // Compares the reference and test arrays over a region around the expected
1895 // delay. Finds the highest SNR in that region and adds the variance and squared
1896 // error results to the supplied accumulators.
UpdateBestSNR(const float * ref,const float * test,size_t length,int expected_delay,double * variance_acc,double * sq_error_acc)1897 void UpdateBestSNR(const float* ref,
1898 const float* test,
1899 size_t length,
1900 int expected_delay,
1901 double* variance_acc,
1902 double* sq_error_acc) {
1903 RTC_CHECK_LT(expected_delay, length)
1904 << "delay greater than signal length, cannot compute SNR";
1905 double best_snr = std::numeric_limits<double>::min();
1906 double best_variance = 0;
1907 double best_sq_error = 0;
1908 // Search over a region of nine samples around the expected delay.
1909 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1910 ++delay) {
1911 double sq_error = 0;
1912 double variance = 0;
1913 for (size_t i = 0; i < length - delay; ++i) {
1914 double error = test[i + delay] - ref[i];
1915 sq_error += error * error;
1916 variance += ref[i] * ref[i];
1917 }
1918
1919 if (sq_error == 0) {
1920 *variance_acc += variance;
1921 return;
1922 }
1923 double snr = variance / sq_error;
1924 if (snr > best_snr) {
1925 best_snr = snr;
1926 best_variance = variance;
1927 best_sq_error = sq_error;
1928 }
1929 }
1930
1931 *variance_acc += best_variance;
1932 *sq_error_acc += best_sq_error;
1933 }
1934
1935 // Used to test a multitude of sample rate and channel combinations. It works
1936 // by first producing a set of reference files (in SetUpTestCase) that are
1937 // assumed to be correct, as the used parameters are verified by other tests
1938 // in this collection. Primarily the reference files are all produced at
1939 // "native" rates which do not involve any resampling.
1940
1941 // Each test pass produces an output file with a particular format. The output
1942 // is matched against the reference file closest to its internal processing
1943 // format. If necessary the output is resampled back to its process format.
1944 // Due to the resampling distortion, we don't expect identical results, but
1945 // enforce SNR thresholds which vary depending on the format. 0 is a special
1946 // case SNR which corresponds to inf, or zero error.
1947 typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
1948 class AudioProcessingTest
1949 : public ::testing::TestWithParam<AudioProcessingTestData> {
1950 public:
AudioProcessingTest()1951 AudioProcessingTest()
1952 : input_rate_(std::get<0>(GetParam())),
1953 output_rate_(std::get<1>(GetParam())),
1954 reverse_input_rate_(std::get<2>(GetParam())),
1955 reverse_output_rate_(std::get<3>(GetParam())),
1956 expected_snr_(std::get<4>(GetParam())),
1957 expected_reverse_snr_(std::get<5>(GetParam())) {}
1958
~AudioProcessingTest()1959 virtual ~AudioProcessingTest() {}
1960
SetUpTestSuite()1961 static void SetUpTestSuite() {
1962 // Create all needed output reference files.
1963 const size_t kNumChannels[] = {1, 2};
1964 for (size_t i = 0; i < arraysize(kProcessSampleRates); ++i) {
1965 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1966 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
1967 // The reference files always have matching input and output channels.
1968 ProcessFormat(kProcessSampleRates[i], kProcessSampleRates[i],
1969 kProcessSampleRates[i], kProcessSampleRates[i],
1970 kNumChannels[j], kNumChannels[j], kNumChannels[k],
1971 kNumChannels[k], "ref");
1972 }
1973 }
1974 }
1975 }
1976
TearDown()1977 void TearDown() {
1978 // Remove "out" files after each test.
1979 ClearTempOutFiles();
1980 }
1981
TearDownTestSuite()1982 static void TearDownTestSuite() { ClearTempFiles(); }
1983
1984 // Runs a process pass on files with the given parameters and dumps the output
1985 // to a file specified with `output_file_prefix`. Both forward and reverse
1986 // output streams are dumped.
ProcessFormat(int input_rate,int output_rate,int reverse_input_rate,int reverse_output_rate,size_t num_input_channels,size_t num_output_channels,size_t num_reverse_input_channels,size_t num_reverse_output_channels,absl::string_view output_file_prefix)1987 static void ProcessFormat(int input_rate,
1988 int output_rate,
1989 int reverse_input_rate,
1990 int reverse_output_rate,
1991 size_t num_input_channels,
1992 size_t num_output_channels,
1993 size_t num_reverse_input_channels,
1994 size_t num_reverse_output_channels,
1995 absl::string_view output_file_prefix) {
1996 AudioProcessing::Config apm_config;
1997 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1998 rtc::scoped_refptr<AudioProcessing> ap =
1999 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
2000
2001 EnableAllAPComponents(ap.get());
2002
2003 ProcessingConfig processing_config = {
2004 {{input_rate, num_input_channels},
2005 {output_rate, num_output_channels},
2006 {reverse_input_rate, num_reverse_input_channels},
2007 {reverse_output_rate, num_reverse_output_channels}}};
2008 ap->Initialize(processing_config);
2009
2010 FILE* far_file =
2011 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
2012 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
2013 FILE* out_file = fopen(
2014 OutputFilePath(
2015 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2016 reverse_output_rate, num_input_channels, num_output_channels,
2017 num_reverse_input_channels, num_reverse_output_channels, kForward)
2018 .c_str(),
2019 "wb");
2020 FILE* rev_out_file = fopen(
2021 OutputFilePath(
2022 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2023 reverse_output_rate, num_input_channels, num_output_channels,
2024 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2025 .c_str(),
2026 "wb");
2027 ASSERT_TRUE(far_file != NULL);
2028 ASSERT_TRUE(near_file != NULL);
2029 ASSERT_TRUE(out_file != NULL);
2030 ASSERT_TRUE(rev_out_file != NULL);
2031
2032 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate),
2033 num_input_channels);
2034 ChannelBuffer<float> rev_cb(
2035 AudioProcessing::GetFrameSize(reverse_input_rate),
2036 num_reverse_input_channels);
2037 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate),
2038 num_output_channels);
2039 ChannelBuffer<float> rev_out_cb(
2040 AudioProcessing::GetFrameSize(reverse_output_rate),
2041 num_reverse_output_channels);
2042
2043 // Temporary buffers.
2044 const int max_length =
2045 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2046 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
2047 std::unique_ptr<float[]> float_data(new float[max_length]);
2048 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
2049
2050 int analog_level = 127;
2051 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2052 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
2053 EXPECT_NOERR(ap->ProcessReverseStream(
2054 rev_cb.channels(), processing_config.reverse_input_stream(),
2055 processing_config.reverse_output_stream(), rev_out_cb.channels()));
2056
2057 EXPECT_NOERR(ap->set_stream_delay_ms(0));
2058 ap->set_stream_analog_level(analog_level);
2059
2060 EXPECT_NOERR(ap->ProcessStream(
2061 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2062 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
2063
2064 // Dump forward output to file.
2065 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
2066 float_data.get());
2067 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
2068
2069 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2070 out_length, out_file));
2071
2072 // Dump reverse output to file.
2073 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2074 rev_out_cb.num_channels(), float_data.get());
2075 size_t rev_out_length =
2076 rev_out_cb.num_channels() * rev_out_cb.num_frames();
2077
2078 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2079 rev_out_length, rev_out_file));
2080
2081 analog_level = ap->recommended_stream_analog_level();
2082 }
2083 fclose(far_file);
2084 fclose(near_file);
2085 fclose(out_file);
2086 fclose(rev_out_file);
2087 }
2088
2089 protected:
2090 int input_rate_;
2091 int output_rate_;
2092 int reverse_input_rate_;
2093 int reverse_output_rate_;
2094 double expected_snr_;
2095 double expected_reverse_snr_;
2096 };
2097
TEST_P(AudioProcessingTest,Formats)2098 TEST_P(AudioProcessingTest, Formats) {
2099 struct ChannelFormat {
2100 int num_input;
2101 int num_output;
2102 int num_reverse_input;
2103 int num_reverse_output;
2104 };
2105 ChannelFormat cf[] = {
2106 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2107 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
2108 };
2109
2110 for (size_t i = 0; i < arraysize(cf); ++i) {
2111 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2112 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2113 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
2114
2115 // Verify output for both directions.
2116 std::vector<StreamDirection> stream_directions;
2117 stream_directions.push_back(kForward);
2118 stream_directions.push_back(kReverse);
2119 for (StreamDirection file_direction : stream_directions) {
2120 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2121 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2122 const int out_num =
2123 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2124 const double expected_snr =
2125 file_direction ? expected_reverse_snr_ : expected_snr_;
2126
2127 const int min_ref_rate = std::min(in_rate, out_rate);
2128 int ref_rate;
2129 if (min_ref_rate > 32000) {
2130 ref_rate = 48000;
2131 } else if (min_ref_rate > 16000) {
2132 ref_rate = 32000;
2133 } else {
2134 ref_rate = 16000;
2135 }
2136
2137 FILE* out_file = fopen(
2138 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2139 reverse_output_rate_, cf[i].num_input,
2140 cf[i].num_output, cf[i].num_reverse_input,
2141 cf[i].num_reverse_output, file_direction)
2142 .c_str(),
2143 "rb");
2144 // The reference files always have matching input and output channels.
2145 FILE* ref_file =
2146 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2147 cf[i].num_output, cf[i].num_output,
2148 cf[i].num_reverse_output,
2149 cf[i].num_reverse_output, file_direction)
2150 .c_str(),
2151 "rb");
2152 ASSERT_TRUE(out_file != NULL);
2153 ASSERT_TRUE(ref_file != NULL);
2154
2155 const size_t ref_length =
2156 AudioProcessing::GetFrameSize(ref_rate) * out_num;
2157 const size_t out_length =
2158 AudioProcessing::GetFrameSize(out_rate) * out_num;
2159 // Data from the reference file.
2160 std::unique_ptr<float[]> ref_data(new float[ref_length]);
2161 // Data from the output file.
2162 std::unique_ptr<float[]> out_data(new float[out_length]);
2163 // Data from the resampled output, in case the reference and output rates
2164 // don't match.
2165 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
2166
2167 PushResampler<float> resampler;
2168 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
2169
2170 // Compute the resampling delay of the output relative to the reference,
2171 // to find the region over which we should search for the best SNR.
2172 float expected_delay_sec = 0;
2173 if (in_rate != ref_rate) {
2174 // Input resampling delay.
2175 expected_delay_sec +=
2176 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2177 }
2178 if (out_rate != ref_rate) {
2179 // Output resampling delay.
2180 expected_delay_sec +=
2181 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2182 // Delay of converting the output back to its processing rate for
2183 // testing.
2184 expected_delay_sec +=
2185 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2186 }
2187 // The delay is multiplied by the number of channels because
2188 // UpdateBestSNR() computes the SNR over interleaved data without taking
2189 // channels into account.
2190 int expected_delay =
2191 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
2192
2193 double variance = 0;
2194 double sq_error = 0;
2195 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2196 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2197 float* out_ptr = out_data.get();
2198 if (out_rate != ref_rate) {
2199 // Resample the output back to its internal processing rate if
2200 // necessary.
2201 ASSERT_EQ(ref_length,
2202 static_cast<size_t>(resampler.Resample(
2203 out_ptr, out_length, cmp_data.get(), ref_length)));
2204 out_ptr = cmp_data.get();
2205 }
2206
2207 // Update the `sq_error` and `variance` accumulators with the highest
2208 // SNR of reference vs output.
2209 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2210 &variance, &sq_error);
2211 }
2212
2213 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2214 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2215 << cf[i].num_input << ", " << cf[i].num_output << ", "
2216 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2217 << ", " << file_direction << "): ";
2218 if (sq_error > 0) {
2219 double snr = 10 * log10(variance / sq_error);
2220 EXPECT_GE(snr, expected_snr);
2221 EXPECT_NE(0, expected_snr);
2222 std::cout << "SNR=" << snr << " dB" << std::endl;
2223 } else {
2224 std::cout << "SNR=inf dB" << std::endl;
2225 }
2226
2227 fclose(out_file);
2228 fclose(ref_file);
2229 }
2230 }
2231 }
2232
2233 #if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
2234 INSTANTIATE_TEST_SUITE_P(
2235 CommonFormats,
2236 AudioProcessingTest,
2237 // Internal processing rates and the particularly common sample rate 44100
2238 // Hz are tested in a grid of combinations (capture in, render in, out).
2239 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2240 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2241 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2242 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2243 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2244 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2245 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2246 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2247 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2248 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2249 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2250 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
2251
2252 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2253 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2254 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2255 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2256 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2257 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2258 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2259 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2260 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2261 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2262 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2263 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
2264
2265 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2266 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2267 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
2268 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2269 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2270 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2271 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2272 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
2273 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
2274 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2275 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2276 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
2277
2278 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2279 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2280 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
2281 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2282 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2283 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2284 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2285 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2286 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2287 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
2288 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
2289 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2290
2291 // Other sample rates are not tested exhaustively, to keep
2292 // the test runtime manageable.
2293 //
2294 // Testing most other sample rates logged by Chrome UMA:
2295 // - WebRTC.AudioInputSampleRate
2296 // - WebRTC.AudioOutputSampleRate
2297 // ApmConfiguration.HandlingOfRateCombinations covers
2298 // remaining sample rates.
2299 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2300 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2301 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2302 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2303 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
2304
2305 #elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
2306 INSTANTIATE_TEST_SUITE_P(
2307 CommonFormats,
2308 AudioProcessingTest,
2309 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2310 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2311 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
2312 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2313 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2314 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
2315 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2316 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2317 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
2318 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2319 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2320 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
2321
2322 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2323 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2324 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2325 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2326 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2327 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
2328 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2329 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2330 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2331 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2332 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2333 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
2334
2335 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2336 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2337 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
2338 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2339 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2340 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
2341 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
2342 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
2343 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
2344 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2345 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2346 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
2347
2348 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2349 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2350 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
2351 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2352 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2353 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2354 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
2355 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
2356 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2357 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2358 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
2359 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2360
2361 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2362 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2363 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2364 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2365 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
2366 #endif
2367
2368 // Produces a scoped trace debug output.
ProduceDebugText(int render_input_sample_rate_hz,int render_output_sample_rate_hz,int capture_input_sample_rate_hz,int capture_output_sample_rate_hz,size_t render_input_num_channels,size_t render_output_num_channels,size_t capture_input_num_channels,size_t capture_output_num_channels)2369 std::string ProduceDebugText(int render_input_sample_rate_hz,
2370 int render_output_sample_rate_hz,
2371 int capture_input_sample_rate_hz,
2372 int capture_output_sample_rate_hz,
2373 size_t render_input_num_channels,
2374 size_t render_output_num_channels,
2375 size_t capture_input_num_channels,
2376 size_t capture_output_num_channels) {
2377 rtc::StringBuilder ss;
2378 ss << "Sample rates:"
2379 "\n Render input: "
2380 << render_input_sample_rate_hz
2381 << " Hz"
2382 "\n Render output: "
2383 << render_output_sample_rate_hz
2384 << " Hz"
2385 "\n Capture input: "
2386 << capture_input_sample_rate_hz
2387 << " Hz"
2388 "\n Capture output: "
2389 << capture_output_sample_rate_hz
2390 << " Hz"
2391 "\nNumber of channels:"
2392 "\n Render input: "
2393 << render_input_num_channels
2394 << "\n Render output: " << render_output_num_channels
2395 << "\n Capture input: " << capture_input_num_channels
2396 << "\n Capture output: " << capture_output_num_channels;
2397 return ss.Release();
2398 }
2399
2400 // Validates that running the audio processing module using various combinations
2401 // of sample rates and number of channels works as intended.
RunApmRateAndChannelTest(rtc::ArrayView<const int> sample_rates_hz,rtc::ArrayView<const int> render_channel_counts,rtc::ArrayView<const int> capture_channel_counts)2402 void RunApmRateAndChannelTest(
2403 rtc::ArrayView<const int> sample_rates_hz,
2404 rtc::ArrayView<const int> render_channel_counts,
2405 rtc::ArrayView<const int> capture_channel_counts) {
2406 webrtc::AudioProcessing::Config apm_config;
2407 apm_config.pipeline.multi_channel_render = true;
2408 apm_config.pipeline.multi_channel_capture = true;
2409 apm_config.echo_canceller.enabled = true;
2410 rtc::scoped_refptr<AudioProcessing> apm =
2411 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
2412
2413 StreamConfig render_input_stream_config;
2414 StreamConfig render_output_stream_config;
2415 StreamConfig capture_input_stream_config;
2416 StreamConfig capture_output_stream_config;
2417
2418 std::vector<float> render_input_frame_channels;
2419 std::vector<float*> render_input_frame;
2420 std::vector<float> render_output_frame_channels;
2421 std::vector<float*> render_output_frame;
2422 std::vector<float> capture_input_frame_channels;
2423 std::vector<float*> capture_input_frame;
2424 std::vector<float> capture_output_frame_channels;
2425 std::vector<float*> capture_output_frame;
2426
2427 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2428 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2429 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2430 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2431 for (size_t render_input_num_channels : render_channel_counts) {
2432 for (size_t capture_input_num_channels : capture_channel_counts) {
2433 size_t render_output_num_channels = render_input_num_channels;
2434 size_t capture_output_num_channels = capture_input_num_channels;
2435 auto populate_audio_frame = [](int sample_rate_hz,
2436 size_t num_channels,
2437 StreamConfig* cfg,
2438 std::vector<float>* channels_data,
2439 std::vector<float*>* frame_data) {
2440 cfg->set_sample_rate_hz(sample_rate_hz);
2441 cfg->set_num_channels(num_channels);
2442
2443 size_t max_frame_size =
2444 AudioProcessing::GetFrameSize(sample_rate_hz);
2445 channels_data->resize(num_channels * max_frame_size);
2446 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2447 frame_data->resize(num_channels);
2448 for (size_t channel = 0; channel < num_channels; ++channel) {
2449 (*frame_data)[channel] =
2450 &(*channels_data)[channel * max_frame_size];
2451 }
2452 };
2453
2454 populate_audio_frame(
2455 render_input_sample_rate_hz, render_input_num_channels,
2456 &render_input_stream_config, &render_input_frame_channels,
2457 &render_input_frame);
2458 populate_audio_frame(
2459 render_output_sample_rate_hz, render_output_num_channels,
2460 &render_output_stream_config, &render_output_frame_channels,
2461 &render_output_frame);
2462 populate_audio_frame(
2463 capture_input_sample_rate_hz, capture_input_num_channels,
2464 &capture_input_stream_config, &capture_input_frame_channels,
2465 &capture_input_frame);
2466 populate_audio_frame(
2467 capture_output_sample_rate_hz, capture_output_num_channels,
2468 &capture_output_stream_config, &capture_output_frame_channels,
2469 &capture_output_frame);
2470
2471 for (size_t frame = 0; frame < 2; ++frame) {
2472 SCOPED_TRACE(ProduceDebugText(
2473 render_input_sample_rate_hz, render_output_sample_rate_hz,
2474 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2475 render_input_num_channels, render_output_num_channels,
2476 render_input_num_channels, capture_output_num_channels));
2477
2478 int result = apm->ProcessReverseStream(
2479 &render_input_frame[0], render_input_stream_config,
2480 render_output_stream_config, &render_output_frame[0]);
2481 EXPECT_EQ(result, AudioProcessing::kNoError);
2482 result = apm->ProcessStream(
2483 &capture_input_frame[0], capture_input_stream_config,
2484 capture_output_stream_config, &capture_output_frame[0]);
2485 EXPECT_EQ(result, AudioProcessing::kNoError);
2486 }
2487 }
2488 }
2489 }
2490 }
2491 }
2492 }
2493 }
2494
Toggle(bool & b)2495 constexpr void Toggle(bool& b) {
2496 b ^= true;
2497 }
2498
2499 } // namespace
2500
TEST(RuntimeSettingTest,TestDefaultCtor)2501 TEST(RuntimeSettingTest, TestDefaultCtor) {
2502 auto s = AudioProcessing::RuntimeSetting();
2503 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2504 }
2505
TEST(RuntimeSettingTest,TestUsageWithSwapQueue)2506 TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2507 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2508 auto s = AudioProcessing::RuntimeSetting();
2509 ASSERT_TRUE(q.Insert(&s));
2510 ASSERT_TRUE(q.Remove(&s));
2511 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2512 }
2513
TEST(ApmConfiguration,EnablePostProcessing)2514 TEST(ApmConfiguration, EnablePostProcessing) {
2515 // Verify that apm uses a capture post processing module if one is provided.
2516 auto mock_post_processor_ptr =
2517 new ::testing::NiceMock<test::MockCustomProcessing>();
2518 auto mock_post_processor =
2519 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
2520 rtc::scoped_refptr<AudioProcessing> apm =
2521 AudioProcessingBuilderForTesting()
2522 .SetCapturePostProcessing(std::move(mock_post_processor))
2523 .Create();
2524
2525 Int16FrameData audio;
2526 audio.num_channels = 1;
2527 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2528
2529 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
2530 apm->ProcessStream(audio.data.data(),
2531 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2532 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2533 audio.data.data());
2534 }
2535
TEST(ApmConfiguration,EnablePreProcessing)2536 TEST(ApmConfiguration, EnablePreProcessing) {
2537 // Verify that apm uses a capture post processing module if one is provided.
2538 auto mock_pre_processor_ptr =
2539 new ::testing::NiceMock<test::MockCustomProcessing>();
2540 auto mock_pre_processor =
2541 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2542 rtc::scoped_refptr<AudioProcessing> apm =
2543 AudioProcessingBuilderForTesting()
2544 .SetRenderPreProcessing(std::move(mock_pre_processor))
2545 .Create();
2546
2547 Int16FrameData audio;
2548 audio.num_channels = 1;
2549 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2550
2551 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
2552 apm->ProcessReverseStream(
2553 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2554 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2555 audio.data.data());
2556 }
2557
TEST(ApmConfiguration,EnableCaptureAnalyzer)2558 TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2559 // Verify that apm uses a capture analyzer if one is provided.
2560 auto mock_capture_analyzer_ptr =
2561 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
2562 auto mock_capture_analyzer =
2563 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2564 rtc::scoped_refptr<AudioProcessing> apm =
2565 AudioProcessingBuilderForTesting()
2566 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2567 .Create();
2568
2569 Int16FrameData audio;
2570 audio.num_channels = 1;
2571 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2572
2573 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
2574 apm->ProcessStream(audio.data.data(),
2575 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2576 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2577 audio.data.data());
2578 }
2579
TEST(ApmConfiguration,PreProcessingReceivesRuntimeSettings)2580 TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2581 auto mock_pre_processor_ptr =
2582 new ::testing::NiceMock<test::MockCustomProcessing>();
2583 auto mock_pre_processor =
2584 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2585 rtc::scoped_refptr<AudioProcessing> apm =
2586 AudioProcessingBuilderForTesting()
2587 .SetRenderPreProcessing(std::move(mock_pre_processor))
2588 .Create();
2589 apm->SetRuntimeSetting(
2590 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2591
2592 // RuntimeSettings forwarded during 'Process*Stream' calls.
2593 // Therefore we have to make one such call.
2594 Int16FrameData audio;
2595 audio.num_channels = 1;
2596 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2597
2598 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2599 .Times(1);
2600 apm->ProcessReverseStream(
2601 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2602 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2603 audio.data.data());
2604 }
2605
2606 class MyEchoControlFactory : public EchoControlFactory {
2607 public:
Create(int sample_rate_hz)2608 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2609 auto ec = new test::MockEchoControl();
2610 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2611 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
2612 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2613 .Times(2);
2614 return std::unique_ptr<EchoControl>(ec);
2615 }
2616
Create(int sample_rate_hz,int num_render_channels,int num_capture_channels)2617 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
2618 int num_render_channels,
2619 int num_capture_channels) {
2620 return Create(sample_rate_hz);
2621 }
2622 };
2623
TEST(ApmConfiguration,EchoControlInjection)2624 TEST(ApmConfiguration, EchoControlInjection) {
2625 // Verify that apm uses an injected echo controller if one is provided.
2626 std::unique_ptr<EchoControlFactory> echo_control_factory(
2627 new MyEchoControlFactory());
2628
2629 rtc::scoped_refptr<AudioProcessing> apm =
2630 AudioProcessingBuilderForTesting()
2631 .SetEchoControlFactory(std::move(echo_control_factory))
2632 .Create();
2633
2634 Int16FrameData audio;
2635 audio.num_channels = 1;
2636 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2637 apm->ProcessStream(audio.data.data(),
2638 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2639 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2640 audio.data.data());
2641 apm->ProcessReverseStream(
2642 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2643 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2644 audio.data.data());
2645 apm->ProcessStream(audio.data.data(),
2646 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2647 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2648 audio.data.data());
2649 }
2650
TEST(ApmConfiguration,EchoDetectorInjection)2651 TEST(ApmConfiguration, EchoDetectorInjection) {
2652 using ::testing::_;
2653 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2654 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2655 EXPECT_CALL(*mock_echo_detector,
2656 Initialize(/*capture_sample_rate_hz=*/16000, _,
2657 /*render_sample_rate_hz=*/16000, _))
2658 .Times(1);
2659 rtc::scoped_refptr<AudioProcessing> apm =
2660 AudioProcessingBuilderForTesting()
2661 .SetEchoDetector(mock_echo_detector)
2662 .Create();
2663
2664 // The echo detector is included in processing when enabled.
2665 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2666 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2667 EXPECT_EQ(render_audio.size(), 160u);
2668 });
2669 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2670 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2671 EXPECT_EQ(capture_audio.size(), 160u);
2672 });
2673 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2674
2675 Int16FrameData frame;
2676 frame.num_channels = 1;
2677 SetFrameSampleRate(&frame, 16000);
2678
2679 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2680 StreamConfig(16000, 1), frame.data.data());
2681 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2682 StreamConfig(16000, 1), frame.data.data());
2683
2684 // When processing rates change, the echo detector is also reinitialized to
2685 // match those.
2686 EXPECT_CALL(*mock_echo_detector,
2687 Initialize(/*capture_sample_rate_hz=*/48000, _,
2688 /*render_sample_rate_hz=*/16000, _))
2689 .Times(1);
2690 EXPECT_CALL(*mock_echo_detector,
2691 Initialize(/*capture_sample_rate_hz=*/48000, _,
2692 /*render_sample_rate_hz=*/48000, _))
2693 .Times(1);
2694 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2695 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2696 EXPECT_EQ(render_audio.size(), 480u);
2697 });
2698 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2699 .Times(2)
2700 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2701 EXPECT_EQ(capture_audio.size(), 480u);
2702 });
2703 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2704
2705 SetFrameSampleRate(&frame, 48000);
2706 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2707 StreamConfig(48000, 1), frame.data.data());
2708 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2709 StreamConfig(48000, 1), frame.data.data());
2710 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2711 StreamConfig(48000, 1), frame.data.data());
2712 }
2713
CreateApm(bool mobile_aec)2714 rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2715 // Enable residual echo detection, for stats.
2716 rtc::scoped_refptr<AudioProcessing> apm =
2717 AudioProcessingBuilderForTesting()
2718 .SetEchoDetector(CreateEchoDetector())
2719 .Create();
2720 if (!apm) {
2721 return apm;
2722 }
2723
2724 ProcessingConfig processing_config = {
2725 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2726
2727 if (apm->Initialize(processing_config) != 0) {
2728 return nullptr;
2729 }
2730
2731 // Disable all components except for an AEC.
2732 AudioProcessing::Config apm_config;
2733 apm_config.high_pass_filter.enabled = false;
2734 apm_config.gain_controller1.enabled = false;
2735 apm_config.gain_controller2.enabled = false;
2736 apm_config.echo_canceller.enabled = true;
2737 apm_config.echo_canceller.mobile_mode = mobile_aec;
2738 apm_config.noise_suppression.enabled = false;
2739 apm->ApplyConfig(apm_config);
2740 return apm;
2741 }
2742
2743 #if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2744 #define MAYBE_ApmStatistics DISABLED_ApmStatistics
2745 #else
2746 #define MAYBE_ApmStatistics ApmStatistics
2747 #endif
2748
TEST(MAYBE_ApmStatistics,AECEnabledTest)2749 TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2750 // Set up APM with AEC3 and process some audio.
2751 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
2752 ASSERT_TRUE(apm);
2753 AudioProcessing::Config apm_config;
2754 apm_config.echo_canceller.enabled = true;
2755 apm->ApplyConfig(apm_config);
2756
2757 // Set up an audioframe.
2758 Int16FrameData frame;
2759 frame.num_channels = 1;
2760 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2761
2762 // Fill the audio frame with a sawtooth pattern.
2763 int16_t* ptr = frame.data.data();
2764 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2765 ptr[i] = 10000 * ((i % 3) - 1);
2766 }
2767
2768 // Do some processing.
2769 for (int i = 0; i < 200; i++) {
2770 EXPECT_EQ(apm->ProcessReverseStream(
2771 frame.data.data(),
2772 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2773 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2774 frame.data.data()),
2775 0);
2776 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
2777 EXPECT_EQ(apm->ProcessStream(
2778 frame.data.data(),
2779 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2780 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2781 frame.data.data()),
2782 0);
2783 }
2784
2785 // Test statistics interface.
2786 AudioProcessingStats stats = apm->GetStatistics();
2787 // We expect all statistics to be set and have a sensible value.
2788 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2789 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2790 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2791 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2792 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2793 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2794 ASSERT_TRUE(stats.echo_return_loss.has_value());
2795 EXPECT_NE(*stats.echo_return_loss, -100.0);
2796 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
2797 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
2798 }
2799
TEST(MAYBE_ApmStatistics,AECMEnabledTest)2800 TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2801 // Set up APM with AECM and process some audio.
2802 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
2803 ASSERT_TRUE(apm);
2804
2805 // Set up an audioframe.
2806 Int16FrameData frame;
2807 frame.num_channels = 1;
2808 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2809
2810 // Fill the audio frame with a sawtooth pattern.
2811 int16_t* ptr = frame.data.data();
2812 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2813 ptr[i] = 10000 * ((i % 3) - 1);
2814 }
2815
2816 // Do some processing.
2817 for (int i = 0; i < 200; i++) {
2818 EXPECT_EQ(apm->ProcessReverseStream(
2819 frame.data.data(),
2820 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2821 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2822 frame.data.data()),
2823 0);
2824 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
2825 EXPECT_EQ(apm->ProcessStream(
2826 frame.data.data(),
2827 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2828 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2829 frame.data.data()),
2830 0);
2831 }
2832
2833 // Test statistics interface.
2834 AudioProcessingStats stats = apm->GetStatistics();
2835 // We expect only the residual echo detector statistics to be set and have a
2836 // sensible value.
2837 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2838 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2839 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2840 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2841 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2842 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2843 EXPECT_FALSE(stats.echo_return_loss.has_value());
2844 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
2845 }
2846
TEST(ApmStatistics,DoNotReportVoiceDetectedStat)2847 TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
2848 ProcessingConfig processing_config = {
2849 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2850
2851 // Set up an audioframe.
2852 Int16FrameData frame;
2853 frame.num_channels = 1;
2854 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2855
2856 // Fill the audio frame with a sawtooth pattern.
2857 int16_t* ptr = frame.data.data();
2858 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2859 ptr[i] = 10000 * ((i % 3) - 1);
2860 }
2861
2862 rtc::scoped_refptr<AudioProcessing> apm =
2863 AudioProcessingBuilderForTesting().Create();
2864 apm->Initialize(processing_config);
2865
2866 // No metric should be reported.
2867 EXPECT_EQ(
2868 apm->ProcessStream(frame.data.data(),
2869 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2870 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2871 frame.data.data()),
2872 0);
2873 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
2874 }
2875
TEST(ApmStatistics,GetStatisticsReportsNoEchoDetectorStatsWhenDisabled)2876 TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2877 rtc::scoped_refptr<AudioProcessing> apm =
2878 AudioProcessingBuilderForTesting().Create();
2879 Int16FrameData frame;
2880 frame.num_channels = 1;
2881 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2882 ASSERT_EQ(
2883 apm->ProcessStream(frame.data.data(),
2884 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2885 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2886 frame.data.data()),
2887 0);
2888 // Echo detector is disabled by default, no stats reported.
2889 AudioProcessingStats stats = apm->GetStatistics();
2890 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2891 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2892 }
2893
TEST(ApmStatistics,GetStatisticsReportsEchoDetectorStatsWhenEnabled)2894 TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2895 // Create APM with an echo detector injected.
2896 rtc::scoped_refptr<AudioProcessing> apm =
2897 AudioProcessingBuilderForTesting()
2898 .SetEchoDetector(CreateEchoDetector())
2899 .Create();
2900 Int16FrameData frame;
2901 frame.num_channels = 1;
2902 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2903 // Echo detector enabled: Report stats.
2904 ASSERT_EQ(
2905 apm->ProcessStream(frame.data.data(),
2906 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2907 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2908 frame.data.data()),
2909 0);
2910 AudioProcessingStats stats = apm->GetStatistics();
2911 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2912 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2913 }
2914
TEST(ApmConfiguration,HandlingOfRateAndChannelCombinations)2915 TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2916 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2917 std::array<int, 2> render_channel_counts = {1, 7};
2918 std::array<int, 2> capture_channel_counts = {1, 7};
2919 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2920 capture_channel_counts);
2921 }
2922
TEST(ApmConfiguration,HandlingOfChannelCombinations)2923 TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2924 std::array<int, 1> sample_rates_hz = {48000};
2925 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2926 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2927 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2928 capture_channel_counts);
2929 }
2930
TEST(ApmConfiguration,HandlingOfRateCombinations)2931 TEST(ApmConfiguration, HandlingOfRateCombinations) {
2932 // Test rates <= 96000 logged by Chrome UMA:
2933 // - WebRTC.AudioInputSampleRate
2934 // - WebRTC.AudioOutputSampleRate
2935 // Higher rates are tested in AudioProcessingTest.Format, to keep the number
2936 // of combinations in this test manageable.
2937 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2938 44100, 48000, 88200, 96000};
2939 std::array<int, 1> render_channel_counts = {2};
2940 std::array<int, 1> capture_channel_counts = {2};
2941 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2942 capture_channel_counts);
2943 }
2944
TEST(ApmConfiguration,SelfAssignment)2945 TEST(ApmConfiguration, SelfAssignment) {
2946 // At some point memory sanitizer was complaining about self-assigment.
2947 // Make sure we don't regress.
2948 AudioProcessing::Config config;
2949 AudioProcessing::Config* config2 = &config;
2950 *config2 = *config2; // Workaround -Wself-assign-overloaded
2951 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2952 }
2953
TEST(AudioProcessing,GainController1ConfigEqual)2954 TEST(AudioProcessing, GainController1ConfigEqual) {
2955 AudioProcessing::Config::GainController1 a;
2956 AudioProcessing::Config::GainController1 b;
2957 EXPECT_EQ(a, b);
2958
2959 Toggle(a.enabled);
2960 b.enabled = a.enabled;
2961 EXPECT_EQ(a, b);
2962
2963 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2964 b.mode = a.mode;
2965 EXPECT_EQ(a, b);
2966
2967 a.target_level_dbfs++;
2968 b.target_level_dbfs = a.target_level_dbfs;
2969 EXPECT_EQ(a, b);
2970
2971 a.compression_gain_db++;
2972 b.compression_gain_db = a.compression_gain_db;
2973 EXPECT_EQ(a, b);
2974
2975 Toggle(a.enable_limiter);
2976 b.enable_limiter = a.enable_limiter;
2977 EXPECT_EQ(a, b);
2978
2979 auto& a_analog = a.analog_gain_controller;
2980 auto& b_analog = b.analog_gain_controller;
2981
2982 Toggle(a_analog.enabled);
2983 b_analog.enabled = a_analog.enabled;
2984 EXPECT_EQ(a, b);
2985
2986 a_analog.startup_min_volume++;
2987 b_analog.startup_min_volume = a_analog.startup_min_volume;
2988 EXPECT_EQ(a, b);
2989
2990 a_analog.clipped_level_min++;
2991 b_analog.clipped_level_min = a_analog.clipped_level_min;
2992 EXPECT_EQ(a, b);
2993
2994 Toggle(a_analog.enable_digital_adaptive);
2995 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2996 EXPECT_EQ(a, b);
2997 }
2998
2999 // Checks that one differing parameter is sufficient to make two configs
3000 // different.
TEST(AudioProcessing,GainController1ConfigNotEqual)3001 TEST(AudioProcessing, GainController1ConfigNotEqual) {
3002 AudioProcessing::Config::GainController1 a;
3003 const AudioProcessing::Config::GainController1 b;
3004
3005 Toggle(a.enabled);
3006 EXPECT_NE(a, b);
3007 a = b;
3008
3009 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
3010 EXPECT_NE(a, b);
3011 a = b;
3012
3013 a.target_level_dbfs++;
3014 EXPECT_NE(a, b);
3015 a = b;
3016
3017 a.compression_gain_db++;
3018 EXPECT_NE(a, b);
3019 a = b;
3020
3021 Toggle(a.enable_limiter);
3022 EXPECT_NE(a, b);
3023 a = b;
3024
3025 auto& a_analog = a.analog_gain_controller;
3026 const auto& b_analog = b.analog_gain_controller;
3027
3028 Toggle(a_analog.enabled);
3029 EXPECT_NE(a, b);
3030 a_analog = b_analog;
3031
3032 a_analog.startup_min_volume++;
3033 EXPECT_NE(a, b);
3034 a_analog = b_analog;
3035
3036 a_analog.clipped_level_min++;
3037 EXPECT_NE(a, b);
3038 a_analog = b_analog;
3039
3040 Toggle(a_analog.enable_digital_adaptive);
3041 EXPECT_NE(a, b);
3042 a_analog = b_analog;
3043 }
3044
TEST(AudioProcessing,GainController2ConfigEqual)3045 TEST(AudioProcessing, GainController2ConfigEqual) {
3046 AudioProcessing::Config::GainController2 a;
3047 AudioProcessing::Config::GainController2 b;
3048 EXPECT_EQ(a, b);
3049
3050 Toggle(a.enabled);
3051 b.enabled = a.enabled;
3052 EXPECT_EQ(a, b);
3053
3054 a.fixed_digital.gain_db += 1.0f;
3055 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3056 EXPECT_EQ(a, b);
3057
3058 auto& a_adaptive = a.adaptive_digital;
3059 auto& b_adaptive = b.adaptive_digital;
3060
3061 Toggle(a_adaptive.enabled);
3062 b_adaptive.enabled = a_adaptive.enabled;
3063 EXPECT_EQ(a, b);
3064
3065 Toggle(a_adaptive.dry_run);
3066 b_adaptive.dry_run = a_adaptive.dry_run;
3067 EXPECT_EQ(a, b);
3068
3069 a_adaptive.headroom_db += 1.0f;
3070 b_adaptive.headroom_db = a_adaptive.headroom_db;
3071 EXPECT_EQ(a, b);
3072
3073 a_adaptive.max_gain_db += 1.0f;
3074 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3075 EXPECT_EQ(a, b);
3076
3077 a_adaptive.initial_gain_db += 1.0f;
3078 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3079 EXPECT_EQ(a, b);
3080
3081 a_adaptive.vad_reset_period_ms++;
3082 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
3083 EXPECT_EQ(a, b);
3084
3085 a_adaptive.adjacent_speech_frames_threshold++;
3086 b_adaptive.adjacent_speech_frames_threshold =
3087 a_adaptive.adjacent_speech_frames_threshold;
3088 EXPECT_EQ(a, b);
3089
3090 a_adaptive.max_gain_change_db_per_second += 1.0f;
3091 b_adaptive.max_gain_change_db_per_second =
3092 a_adaptive.max_gain_change_db_per_second;
3093 EXPECT_EQ(a, b);
3094
3095 a_adaptive.max_output_noise_level_dbfs += 1.0f;
3096 b_adaptive.max_output_noise_level_dbfs =
3097 a_adaptive.max_output_noise_level_dbfs;
3098 EXPECT_EQ(a, b);
3099 }
3100
3101 // Checks that one differing parameter is sufficient to make two configs
3102 // different.
TEST(AudioProcessing,GainController2ConfigNotEqual)3103 TEST(AudioProcessing, GainController2ConfigNotEqual) {
3104 AudioProcessing::Config::GainController2 a;
3105 const AudioProcessing::Config::GainController2 b;
3106
3107 Toggle(a.enabled);
3108 EXPECT_NE(a, b);
3109 a = b;
3110
3111 a.fixed_digital.gain_db += 1.0f;
3112 EXPECT_NE(a, b);
3113 a.fixed_digital = b.fixed_digital;
3114
3115 auto& a_adaptive = a.adaptive_digital;
3116 const auto& b_adaptive = b.adaptive_digital;
3117
3118 Toggle(a_adaptive.enabled);
3119 EXPECT_NE(a, b);
3120 a_adaptive = b_adaptive;
3121
3122 Toggle(a_adaptive.dry_run);
3123 EXPECT_NE(a, b);
3124 a_adaptive = b_adaptive;
3125
3126 a_adaptive.headroom_db += 1.0f;
3127 EXPECT_NE(a, b);
3128 a_adaptive = b_adaptive;
3129
3130 a_adaptive.max_gain_db += 1.0f;
3131 EXPECT_NE(a, b);
3132 a_adaptive = b_adaptive;
3133
3134 a_adaptive.initial_gain_db += 1.0f;
3135 EXPECT_NE(a, b);
3136 a_adaptive = b_adaptive;
3137
3138 a_adaptive.vad_reset_period_ms++;
3139 EXPECT_NE(a, b);
3140 a_adaptive = b_adaptive;
3141
3142 a_adaptive.adjacent_speech_frames_threshold++;
3143 EXPECT_NE(a, b);
3144 a_adaptive = b_adaptive;
3145
3146 a_adaptive.max_gain_change_db_per_second += 1.0f;
3147 EXPECT_NE(a, b);
3148 a_adaptive = b_adaptive;
3149
3150 a_adaptive.max_output_noise_level_dbfs += 1.0f;
3151 EXPECT_NE(a, b);
3152 a_adaptive = b_adaptive;
3153 }
3154
3155 struct ApmFormatHandlingTestParams {
3156 enum class ExpectedOutput {
3157 kErrorAndUnmodified,
3158 kErrorAndSilence,
3159 kErrorAndCopyOfFirstChannel,
3160 kErrorAndExactCopy,
3161 kNoError
3162 };
3163
3164 StreamConfig input_config;
3165 StreamConfig output_config;
3166 ExpectedOutput expected_output;
3167 };
3168
3169 class ApmFormatHandlingTest
3170 : public ::testing::TestWithParam<
3171 std::tuple<StreamDirection, ApmFormatHandlingTestParams>> {
3172 public:
ApmFormatHandlingTest()3173 ApmFormatHandlingTest()
3174 : stream_direction_(std::get<0>(GetParam())),
3175 test_params_(std::get<1>(GetParam())) {}
3176
3177 protected:
ProduceDebugMessage()3178 ::testing::Message ProduceDebugMessage() {
3179 return ::testing::Message()
3180 << "input sample_rate_hz="
3181 << test_params_.input_config.sample_rate_hz()
3182 << " num_channels=" << test_params_.input_config.num_channels()
3183 << ", output sample_rate_hz="
3184 << test_params_.output_config.sample_rate_hz()
3185 << " num_channels=" << test_params_.output_config.num_channels()
3186 << ", stream_direction=" << stream_direction_ << ", expected_output="
3187 << static_cast<int>(test_params_.expected_output);
3188 }
3189
3190 StreamDirection stream_direction_;
3191 ApmFormatHandlingTestParams test_params_;
3192 };
3193
3194 INSTANTIATE_TEST_SUITE_P(
3195 FormatValidation,
3196 ApmFormatHandlingTest,
3197 testing::Combine(
3198 ::testing::Values(kForward, kReverse),
3199 ::testing::Values(
3200 // Test cases with values on the boundary of legal ranges.
3201 ApmFormatHandlingTestParams{
3202 StreamConfig(16000, 1), StreamConfig(8000, 1),
3203 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3204 ApmFormatHandlingTestParams{
3205 StreamConfig(8000, 1), StreamConfig(16000, 1),
3206 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3207 ApmFormatHandlingTestParams{
3208 StreamConfig(384000, 1), StreamConfig(16000, 1),
3209 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3210 ApmFormatHandlingTestParams{
3211 StreamConfig(16000, 1), StreamConfig(384000, 1),
3212 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3213 ApmFormatHandlingTestParams{
3214 StreamConfig(16000, 2), StreamConfig(16000, 1),
3215 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3216 ApmFormatHandlingTestParams{
3217 StreamConfig(16000, 3), StreamConfig(16000, 3),
3218 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3219
3220 // Supported but incompatible formats.
3221 ApmFormatHandlingTestParams{
3222 StreamConfig(16000, 3), StreamConfig(16000, 2),
3223 ApmFormatHandlingTestParams::ExpectedOutput::
3224 kErrorAndCopyOfFirstChannel},
3225 ApmFormatHandlingTestParams{
3226 StreamConfig(16000, 3), StreamConfig(16000, 4),
3227 ApmFormatHandlingTestParams::ExpectedOutput::
3228 kErrorAndCopyOfFirstChannel},
3229
3230 // Unsupported format and input / output mismatch.
3231 ApmFormatHandlingTestParams{
3232 StreamConfig(7900, 1), StreamConfig(16000, 1),
3233 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3234 ApmFormatHandlingTestParams{
3235 StreamConfig(16000, 1), StreamConfig(7900, 1),
3236 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3237 ApmFormatHandlingTestParams{
3238 StreamConfig(390000, 1), StreamConfig(16000, 1),
3239 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3240 ApmFormatHandlingTestParams{
3241 StreamConfig(16000, 1), StreamConfig(390000, 1),
3242 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3243 ApmFormatHandlingTestParams{
3244 StreamConfig(-16000, 1), StreamConfig(16000, 1),
3245 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3246
3247 // Unsupported format but input / output formats match.
3248 ApmFormatHandlingTestParams{StreamConfig(7900, 1),
3249 StreamConfig(7900, 1),
3250 ApmFormatHandlingTestParams::
3251 ExpectedOutput::kErrorAndExactCopy},
3252 ApmFormatHandlingTestParams{StreamConfig(390000, 1),
3253 StreamConfig(390000, 1),
3254 ApmFormatHandlingTestParams::
3255 ExpectedOutput::kErrorAndExactCopy},
3256
3257 // Unsupported but identical sample rate, channel mismatch.
3258 ApmFormatHandlingTestParams{
3259 StreamConfig(7900, 1), StreamConfig(7900, 2),
3260 ApmFormatHandlingTestParams::ExpectedOutput::
3261 kErrorAndCopyOfFirstChannel},
3262 ApmFormatHandlingTestParams{
3263 StreamConfig(7900, 2), StreamConfig(7900, 1),
3264 ApmFormatHandlingTestParams::ExpectedOutput::
3265 kErrorAndCopyOfFirstChannel},
3266
3267 // Test cases with meaningless output format.
3268 ApmFormatHandlingTestParams{
3269 StreamConfig(16000, 1), StreamConfig(-16000, 1),
3270 ApmFormatHandlingTestParams::ExpectedOutput::
3271 kErrorAndUnmodified},
3272 ApmFormatHandlingTestParams{
3273 StreamConfig(-16000, 1), StreamConfig(-16000, 1),
3274 ApmFormatHandlingTestParams::ExpectedOutput::
3275 kErrorAndUnmodified})));
3276
TEST_P(ApmFormatHandlingTest,IntApi)3277 TEST_P(ApmFormatHandlingTest, IntApi) {
3278 SCOPED_TRACE(ProduceDebugMessage());
3279
3280 // Set up input and output data.
3281 const size_t num_input_samples =
3282 test_params_.input_config.num_channels() *
3283 std::abs(test_params_.input_config.sample_rate_hz() / 100);
3284 const size_t num_output_samples =
3285 test_params_.output_config.num_channels() *
3286 std::abs(test_params_.output_config.sample_rate_hz() / 100);
3287 std::vector<int16_t> input_block(num_input_samples);
3288 for (int i = 0; i < static_cast<int>(input_block.size()); ++i) {
3289 input_block[i] = i;
3290 }
3291 std::vector<int16_t> output_block(num_output_samples);
3292 constexpr int kUnlikelyOffset = 37;
3293 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3294 output_block[i] = i - kUnlikelyOffset;
3295 }
3296
3297 // Call APM.
3298 rtc::scoped_refptr<AudioProcessing> ap =
3299 AudioProcessingBuilderForTesting().Create();
3300 int error;
3301 if (stream_direction_ == kForward) {
3302 error = ap->ProcessStream(input_block.data(), test_params_.input_config,
3303 test_params_.output_config, output_block.data());
3304 } else {
3305 error = ap->ProcessReverseStream(
3306 input_block.data(), test_params_.input_config,
3307 test_params_.output_config, output_block.data());
3308 }
3309
3310 // Check output.
3311 switch (test_params_.expected_output) {
3312 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError:
3313 EXPECT_EQ(error, AudioProcessing::kNoError);
3314 break;
3315 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified:
3316 EXPECT_NE(error, AudioProcessing::kNoError);
3317 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3318 EXPECT_EQ(output_block[i], i - kUnlikelyOffset);
3319 }
3320 break;
3321 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence:
3322 EXPECT_NE(error, AudioProcessing::kNoError);
3323 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3324 EXPECT_EQ(output_block[i], 0);
3325 }
3326 break;
3327 case ApmFormatHandlingTestParams::ExpectedOutput::
3328 kErrorAndCopyOfFirstChannel:
3329 EXPECT_NE(error, AudioProcessing::kNoError);
3330 for (size_t ch = 0; ch < test_params_.output_config.num_channels();
3331 ++ch) {
3332 for (size_t i = 0; i < test_params_.output_config.num_frames(); ++i) {
3333 EXPECT_EQ(
3334 output_block[ch + i * test_params_.output_config.num_channels()],
3335 static_cast<int16_t>(i *
3336 test_params_.input_config.num_channels()));
3337 }
3338 }
3339 break;
3340 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy:
3341 EXPECT_NE(error, AudioProcessing::kNoError);
3342 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3343 EXPECT_EQ(output_block[i], i);
3344 }
3345 break;
3346 }
3347 }
3348
TEST_P(ApmFormatHandlingTest,FloatApi)3349 TEST_P(ApmFormatHandlingTest, FloatApi) {
3350 SCOPED_TRACE(ProduceDebugMessage());
3351
3352 // Set up input and output data.
3353 const size_t input_samples_per_channel =
3354 std::abs(test_params_.input_config.sample_rate_hz()) / 100;
3355 const size_t output_samples_per_channel =
3356 std::abs(test_params_.output_config.sample_rate_hz()) / 100;
3357 const size_t input_num_channels = test_params_.input_config.num_channels();
3358 const size_t output_num_channels = test_params_.output_config.num_channels();
3359 ChannelBuffer<float> input_block(input_samples_per_channel,
3360 input_num_channels);
3361 ChannelBuffer<float> output_block(output_samples_per_channel,
3362 output_num_channels);
3363 for (size_t ch = 0; ch < input_num_channels; ++ch) {
3364 for (size_t i = 0; i < input_samples_per_channel; ++i) {
3365 input_block.channels()[ch][i] = ch + i * input_num_channels;
3366 }
3367 }
3368 constexpr int kUnlikelyOffset = 37;
3369 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3370 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3371 output_block.channels()[ch][i] =
3372 ch + i * output_num_channels - kUnlikelyOffset;
3373 }
3374 }
3375
3376 // Call APM.
3377 rtc::scoped_refptr<AudioProcessing> ap =
3378 AudioProcessingBuilderForTesting().Create();
3379 int error;
3380 if (stream_direction_ == kForward) {
3381 error =
3382 ap->ProcessStream(input_block.channels(), test_params_.input_config,
3383 test_params_.output_config, output_block.channels());
3384 } else {
3385 error = ap->ProcessReverseStream(
3386 input_block.channels(), test_params_.input_config,
3387 test_params_.output_config, output_block.channels());
3388 }
3389
3390 // Check output.
3391 switch (test_params_.expected_output) {
3392 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError:
3393 EXPECT_EQ(error, AudioProcessing::kNoError);
3394 break;
3395 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified:
3396 EXPECT_NE(error, AudioProcessing::kNoError);
3397 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3398 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3399 EXPECT_EQ(output_block.channels()[ch][i],
3400 ch + i * output_num_channels - kUnlikelyOffset);
3401 }
3402 }
3403 break;
3404 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence:
3405 EXPECT_NE(error, AudioProcessing::kNoError);
3406 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3407 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3408 EXPECT_EQ(output_block.channels()[ch][i], 0);
3409 }
3410 }
3411 break;
3412 case ApmFormatHandlingTestParams::ExpectedOutput::
3413 kErrorAndCopyOfFirstChannel:
3414 EXPECT_NE(error, AudioProcessing::kNoError);
3415 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3416 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3417 EXPECT_EQ(output_block.channels()[ch][i],
3418 input_block.channels()[0][i]);
3419 }
3420 }
3421 break;
3422 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy:
3423 EXPECT_NE(error, AudioProcessing::kNoError);
3424 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3425 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3426 EXPECT_EQ(output_block.channels()[ch][i],
3427 input_block.channels()[ch][i]);
3428 }
3429 }
3430 break;
3431 }
3432 }
3433
TEST(ApmAnalyzeReverseStreamFormatTest,AnalyzeReverseStream)3434 TEST(ApmAnalyzeReverseStreamFormatTest, AnalyzeReverseStream) {
3435 for (auto&& [input_config, expect_error] :
3436 {std::tuple(StreamConfig(16000, 2), /*expect_error=*/false),
3437 std::tuple(StreamConfig(8000, 1), /*expect_error=*/false),
3438 std::tuple(StreamConfig(384000, 1), /*expect_error=*/false),
3439 std::tuple(StreamConfig(7900, 1), /*expect_error=*/true),
3440 std::tuple(StreamConfig(390000, 1), /*expect_error=*/true),
3441 std::tuple(StreamConfig(16000, 0), /*expect_error=*/true),
3442 std::tuple(StreamConfig(-16000, 0), /*expect_error=*/true)}) {
3443 SCOPED_TRACE(::testing::Message()
3444 << "sample_rate_hz=" << input_config.sample_rate_hz()
3445 << " num_channels=" << input_config.num_channels());
3446
3447 // Set up input data.
3448 ChannelBuffer<float> input_block(
3449 std::abs(input_config.sample_rate_hz()) / 100,
3450 input_config.num_channels());
3451
3452 // Call APM.
3453 rtc::scoped_refptr<AudioProcessing> ap =
3454 AudioProcessingBuilderForTesting().Create();
3455 int error = ap->AnalyzeReverseStream(input_block.channels(), input_config);
3456
3457 // Check output.
3458 if (expect_error) {
3459 EXPECT_NE(error, AudioProcessing::kNoError);
3460 } else {
3461 EXPECT_EQ(error, AudioProcessing::kNoError);
3462 }
3463 }
3464 }
3465
3466 } // namespace webrtc
3467