blob: a0514744c417c91b45e60cb583f2809058e869d4 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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 */
Jonas Olssona4d87372019-07-05 19:08:33 +020010#include "modules/audio_processing/include/audio_processing.h"
11
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000012#include <math.h>
ajm@google.com59e41402011-07-28 17:34:04 +000013#include <stdio.h>
kwiberg62eaacf2016-02-17 06:39:05 -080014
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000015#include <algorithm>
Oleh Prypin708eccc2019-03-27 09:38:52 +010016#include <cmath>
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000017#include <limits>
kwiberg62eaacf2016-02-17 06:39:05 -080018#include <memory>
Sam Zackrissone277bde2019-10-25 10:07:54 +020019#include <numeric>
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000020#include <queue>
Ali Tofighf3592cb2022-08-16 14:44:38 +020021#include <string>
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000022
Sam Zackrisson6558fa52019-08-26 10:12:41 +020023#include "absl/flags/flag.h"
Ali Tofighf3592cb2022-08-16 14:44:38 +020024#include "absl/strings/string_view.h"
Sam Zackrisson03cb7e52021-12-06 15:40:04 +010025#include "api/audio/echo_detector_creator.h"
Niels Möller105711e2022-06-14 15:48:26 +020026#include "api/make_ref_counted.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#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"
Sam Zackrisson0beac582017-09-25 12:04:02 +020033#include "modules/audio_processing/include/mock_audio_processing.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020034#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "modules/audio_processing/test/protobuf_utils.h"
36#include "modules/audio_processing/test/test_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "rtc_base/arraysize.h"
38#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "rtc_base/gtest_prod_util.h"
41#include "rtc_base/ignore_wundef.h"
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +010042#include "rtc_base/numerics/safe_conversions.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010043#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020044#include "rtc_base/protobuf_utils.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020045#include "rtc_base/strings/string_builder.h"
Alessio Bazzicac054e782018-04-16 12:10:09 +020046#include "rtc_base/swap_queue.h"
Niels Möllera12c42a2018-07-25 16:05:48 +020047#include "rtc_base/system/arch.h"
Danil Chapovalov07122bc2019-03-26 14:37:01 +010048#include "rtc_base/task_queue_for_test.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020049#include "rtc_base/thread.h"
Per Åhgrena43178c2020-09-25 12:02:32 +020050#include "system_wrappers/include/cpu_features_wrapper.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020051#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080052#include "test/testsupport/file_utils.h"
kwiberg77eab702016-09-28 17:42:01 -070053
54RTC_PUSH_IGNORING_WUNDEF()
Alessio Bazzica85a126e2022-08-11 15:48:54 +020055#include "modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000056#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000057#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000058#else
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020059#include "modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000060#endif
kwiberg77eab702016-09-28 17:42:01 -070061RTC_POP_IGNORING_WUNDEF()
niklase@google.com470e71d2011-07-07 08:21:25 +000062
Sam Zackrisson6558fa52019-08-26 10:12:41 +020063ABSL_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
andrew@webrtc.org27c69802014-02-18 20:24:56 +000069namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000070namespace {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000071
Sam Zackrisson3bd444f2022-08-03 14:37:00 +020072// All sample rates used by APM internally during processing. Other input /
73// output rates are resampled to / from one of these.
74const int kProcessSampleRates[] = {16000, 32000, 48000};
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000075
ekmeyerson60d9b332015-08-14 10:35:55 -070076enum StreamDirection { kForward = 0, kReverse };
77
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000078void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 19:08:33 +020079 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
80 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000081 cb_int.channels());
Peter Kasting69558702016-01-12 16:26:35 -080082 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +020083 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000084 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000085}
andrew@webrtc.org17e40642014-03-04 20:58:13 +000086
Per Åhgren2507f8c2020-03-19 12:33:29 +010087void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
88 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000089}
90
Jonas Olssona4d87372019-07-05 19:08:33 +020091void MixStereoToMono(const float* stereo,
92 float* mono,
pkasting25702cb2016-01-08 13:50:27 -080093 size_t samples_per_channel) {
94 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000095 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +000096}
97
Jonas Olssona4d87372019-07-05 19:08:33 +020098void MixStereoToMono(const int16_t* stereo,
99 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -0800100 size_t samples_per_channel) {
101 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000102 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
103}
104
pkasting25702cb2016-01-08 13:50:27 -0800105void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
106 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000107 stereo[i * 2 + 1] = stereo[i * 2];
108 }
109}
110
yujo36b1a5f2017-06-12 12:45:32 -0700111void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800112 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000113 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
114 }
115}
116
Per Åhgren2507f8c2020-03-19 12:33:29 +0100117void SetFrameTo(Int16FrameData* frame, int16_t value) {
118 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700119 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100120 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000121 }
122}
123
Per Åhgren2507f8c2020-03-19 12:33:29 +0100124void 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;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000129 }
130}
131
Per Åhgren2507f8c2020-03-19 12:33:29 +0100132void ScaleFrame(Int16FrameData* frame, float scale) {
133 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700134 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100135 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000136 }
137}
138
Per Åhgren2507f8c2020-03-19 12:33:29 +0100139bool FrameDataAreEqual(const Int16FrameData& frame1,
140 const Int16FrameData& frame2) {
141 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000142 return false;
143 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100144 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000145 return false;
146 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100147 if (memcmp(
148 frame1.data.data(), frame2.data.data(),
149 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150 return false;
151 }
152 return true;
153}
154
Per Åhgren2507f8c2020-03-19 12:33:29 +0100155rtc::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;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200158 return rtc::ArrayView<int16_t>(ptr, len);
159}
160
Per Åhgren2507f8c2020-03-19 12:33:29 +0100161rtc::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;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200164 return rtc::ArrayView<const int16_t>(ptr, len);
165}
166
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000167void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200168 AudioProcessing::Config apm_config = ap->GetConfig();
169 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000170#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200171 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100172
173 apm_config.gain_controller1.enabled = true;
174 apm_config.gain_controller1.mode =
175 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000176#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200177 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000178
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100179 apm_config.gain_controller1.enabled = true;
180 apm_config.gain_controller1.mode =
181 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000182#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000183
saza0bad15f2019-10-16 11:46:11 +0200184 apm_config.noise_suppression.enabled = true;
185
peah8271d042016-11-22 07:24:52 -0800186 apm_config.high_pass_filter.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100187 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800188 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000189}
190
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000191// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000192template <class T>
193T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200194 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000195}
196
Per Åhgren2507f8c2020-03-19 12:33:29 +0100197int16_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]);
pkasting25702cb2016-01-08 13:50:27 -0800200 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100201 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000202 }
203
204 return max_data;
205}
206
Ali Tofighf3592cb2022-08-16 14:44:38 +0200207void OpenFileAndWriteMessage(absl::string_view filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700208 const MessageLite& msg) {
Ali Tofighf3592cb2022-08-16 14:44:38 +0200209 FILE* file = fopen(std::string(filename).c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000210 ASSERT_TRUE(file != NULL);
211
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100212 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000213 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800214 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000215 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000216
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000217 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000218 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200219 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000220 fclose(file);
221}
222
Ali Tofighf3592cb2022-08-16 14:44:38 +0200223std::string ResourceFilePath(absl::string_view name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200224 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000225 // Resource files are all stereo.
226 ss << name << sample_rate_hz / 1000 << "_stereo";
227 return test::ResourcePath(ss.str(), "pcm");
228}
229
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000230// 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.
233std::map<std::string, std::string> temp_filenames;
234
Ali Tofighf3592cb2022-08-16 14:44:38 +0200235std::string OutputFilePath(absl::string_view name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000236 int input_rate,
237 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700238 int reverse_input_rate,
239 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800240 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,
ekmeyerson60d9b332015-08-14 10:35:55 -0700244 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200245 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700246 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
247 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000248 if (num_output_channels == 1) {
249 ss << "mono";
250 } else if (num_output_channels == 2) {
251 ss << "stereo";
252 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100253 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000254 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700255 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 {
Artem Titovd3251962021-11-15 16:57:07 +0100261 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700262 }
263 ss << reverse_output_rate / 1000;
264 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000265
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000266 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700267 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000268 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
269 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000270}
271
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000272void ClearTempFiles() {
273 for (auto& kv : temp_filenames)
274 remove(kv.second.c_str());
275}
276
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200277// Only remove "out" files. Keep "ref" files.
278void 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
Ali Tofighf3592cb2022-08-16 14:44:38 +0200290void OpenFileAndReadMessage(absl::string_view filename, MessageLite* msg) {
291 FILE* file = fopen(std::string(filename).c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000292 ASSERT_TRUE(file != NULL);
293 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000294 fclose(file);
295}
296
Sam Zackrisson3bd444f2022-08-03 14:37:00 +0200297// 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.
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000302//
Artem Titov0b489302021-07-28 20:50:03 +0200303// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000304// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200305bool ReadChunk(FILE* file,
306 int16_t* int_data,
307 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000308 ChannelBuffer<float>* cb) {
309 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000310 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000311 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.
kwiberg9e2be5f2016-09-14 05:23:22 -0700314 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000315 return false; // This is expected.
316 }
317
318 S16ToFloat(int_data, frame_size, float_data);
319 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000320 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000321 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200322 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000323 }
324
325 return true;
326}
327
Per Åhgrena43178c2020-09-25 12:02:32 +0200328// Returns the reference file name that matches the current CPU
329// architecture/optimizations.
330std::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
Alessio Bazzica85a126e2022-08-11 15:48:54 +0200341// 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.
344constexpr 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.
348TEST(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.
354void 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.level(), expected.level());
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.
366void 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.
386bool 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
niklase@google.com470e71d2011-07-07 08:21:25 +0000407class ApmTest : public ::testing::Test {
408 protected:
409 ApmTest();
410 virtual void SetUp();
411 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000412
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200413 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000414
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200415 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000416
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000417 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200418 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000419
420 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000421 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000422 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800423 size_t num_input_channels,
424 size_t num_output_channels,
425 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000426 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000427 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000428 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100429 bool ReadFrame(FILE* file, Int16FrameData* frame);
430 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
431 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200432 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100433 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000434 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200435 void ProcessDelayVerificationTest(int delay_ms,
436 int system_delay_ms,
437 int delay_min,
438 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700439 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800440 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700441 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800442 void TestChangingForwardChannels(size_t num_in_channels,
443 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700444 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800445 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700446 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000447 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
448 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000449 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000450 int ProcessStreamChooser(Format format);
451 int AnalyzeReverseStreamChooser(Format format);
Ali Tofighf3592cb2022-08-16 14:44:38 +0200452 void ProcessDebugDump(absl::string_view in_filename,
453 absl::string_view out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800454 Format format,
455 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000456 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000457
458 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000459 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200460 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100461 Int16FrameData frame_;
462 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 15:40:04 +0100463 std::unique_ptr<ChannelBuffer<float>> float_cb_;
464 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000465 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800466 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000467 FILE* far_file_;
468 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000469 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000470};
471
472ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000473 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200474 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000475 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000476 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000477 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000478 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000479 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200480 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100481 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100482 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100483 apm_config.pipeline.maximum_internal_processing_rate = 48000;
484 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000485}
niklase@google.com470e71d2011-07-07 08:21:25 +0000486
487void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000488 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000489
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000490 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000491}
492
493void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000494 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
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000504 if (out_file_) {
505 ASSERT_EQ(0, fclose(out_file_));
506 }
507 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000508}
509
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000510void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200511 ASSERT_EQ(
512 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100513 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200514 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100515 {revframe_.sample_rate_hz, revframe_.num_channels},
516 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000517}
518
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000519void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000520 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000521 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800522 size_t num_input_channels,
523 size_t num_output_channels,
524 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000525 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200526 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000527 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000528 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000529
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200530 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000531 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000532 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000533
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000534 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");
Jonas Olssona4d87372019-07-05 19:08:33 +0200539 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000540
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");
Jonas Olssona4d87372019-07-05 19:08:33 +0200546 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000547
548 if (open_output_file) {
549 if (out_file_) {
550 ASSERT_EQ(0, fclose(out_file_));
551 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700552 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);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000556 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200557 ASSERT_TRUE(out_file_ != NULL)
558 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000559 }
560}
561
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000562void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000563 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000564}
565
Jonas Olssona4d87372019-07-05 19:08:33 +0200566bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100567 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000568 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000569 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100570 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200571 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100572 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000573 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
Per Åhgren2507f8c2020-03-19 12:33:29 +0100579 if (frame->num_channels == 1) {
580 MixStereoToMono(frame->data.data(), frame->data.data(),
581 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000582 }
583
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000584 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000585 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000586 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000587 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000588}
589
Per Åhgren2507f8c2020-03-19 12:33:29 +0100590bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000591 return ReadFrame(file, frame, NULL);
592}
593
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000594// If the end of the file has been reached, rewind it and attempt to read the
595// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200596void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100597 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000598 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200599 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000600 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200601 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000602 }
603}
604
Per Åhgren2507f8c2020-03-19 12:33:29 +0100605void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000606 ReadFrameWithRewind(file, frame, NULL);
607}
608
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000609int ApmTest::ProcessStreamChooser(Format format) {
610 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100611 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100615 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000616 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200617 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100618 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100619 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100620 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200621 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000622}
623
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000624int ApmTest::AnalyzeReverseStreamChooser(Format format) {
625 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100626 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());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000631 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000632 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100633 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100634 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000635}
636
Jonas Olssona4d87372019-07-05 19:08:33 +0200637void ApmTest::ProcessDelayVerificationTest(int delay_ms,
638 int system_delay_ms,
639 int delay_min,
640 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200641 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000642 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100643 Int16FrameData tmp_frame;
644 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000645 bool causal = true;
646
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200647 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000648 SetFrameTo(&tmp_frame, 0);
649
650 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200651 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000652 int frame_delay = delay_ms / 10;
653 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100654 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000655 frame->CopyFrom(tmp_frame);
656 frame_queue.push(frame);
657 frame_delay++;
658 causal = false;
659 }
660 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100661 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000662 frame->CopyFrom(tmp_frame);
663 frame_queue.push(frame);
664 frame_delay--;
665 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000666 // 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.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000670 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100671 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000672 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);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100676 Int16FrameData* reverse_frame = frame;
677 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000678 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 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100686 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()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000693 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100694 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100700 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000701 frame = frame_queue.front();
702 frame_queue.pop();
703 delete frame;
704
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000705 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000706 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100707 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000708 }
709 }
710
711 rewind(near_file_);
712 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100713 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000714 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.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700719 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100720 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700721 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,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700725 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700726 const int expected_median_low = rtc::SafeClamp<int>(
727 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700728 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000729 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100730 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200731 ASSERT_TRUE(stats.delay_median_ms.has_value());
732 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000733 EXPECT_GE(expected_median_high, median);
734 EXPECT_LE(expected_median_low, median);
735}
736
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000737void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000739 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000740
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000741 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200742 AudioProcessing::Config apm_config = apm_->GetConfig();
743 apm_config.gain_controller1.enabled = true;
744 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200745 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000746
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000747 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200748 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000749 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200750 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000751
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000752 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200753 apm_config.echo_canceller.enabled = true;
754 apm_config.echo_canceller.mobile_mode = false;
755 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000756 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200757 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200758 apm_config.gain_controller1.enabled = false;
759 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000760
761 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000762 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100763 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000764
765 // Resets after successful ProcessStream().
766 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000767 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100768 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000769
770 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200771 apm_config.gain_controller1.enabled = true;
772 apm_->ApplyConfig(apm_config);
773 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100774 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200775 apm_config.gain_controller1.enabled = false;
776 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000777
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000778 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200779 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100780 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000781
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000782 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200784 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000785 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000786}
787
788TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000789 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000790}
791
792TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000793 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000794}
795
Michael Graczyk86c6d332015-07-23 11:41:39 -0700796void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800797 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700798 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100799 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100806 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100807 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()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000813}
814
Michael Graczyk86c6d332015-07-23 11:41:39 -0700815void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800816 size_t num_in_channels,
817 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700818 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100819 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700820 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
827void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800828 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700829 AudioProcessing::Error expected_return) {
830 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100831 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700832 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100833 {frame_.sample_rate_hz, num_rev_channels},
834 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700835
ekmeyerson60d9b332015-08-14 10:35:55 -0700836 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()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700841}
842
843TEST_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
Peter Kasting69558702016-01-12 16:26:35 -0800849 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700850 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000851 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000852 }
853}
854
Michael Graczyk86c6d332015-07-23 11:41:39 -0700855TEST_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
Peter Kasting69558702016-01-12 16:26:35 -0800862 for (size_t i = 1; i < 4; ++i) {
863 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700864 // 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.
Peter Kasting69558702016-01-12 16:26:35 -0800872 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700873 } else {
874 TestChangingForwardChannels(i, j,
875 AudioProcessing::kBadNumberChannelsError);
876 }
877 }
878 }
879}
880
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000881TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100882 // 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_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000885 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000886 }
887}
888
Sam Zackrissone277bde2019-10-25 10:07:54 +0200889// This test repeatedly reconfigures the pre-amplifier in APM, processes a
890// number of frames, and checks that output signal has the right level.
891TEST_F(ApmTest, PreAmplifier) {
892 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200893 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100894 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200895 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100896 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200897 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
898 }
899 }
900 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100901 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200902 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200903
Per Åhgren2507f8c2020-03-19 12:33:29 +0100904 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200905 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) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200923 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200924 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
925 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200926 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200927 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) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200936 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200937 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
938 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200939 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200940 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) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200949 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200950 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
951 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200952 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200953 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
Per Åhgrendb5d7282021-03-15 16:31:04 +0000958// This test a simple test that ensures that the emulated analog mic gain
959// functionality runs without crashing.
960TEST_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.
994TEST_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
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001083TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001084 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
niklase@google.com470e71d2011-07-07 08:21:25 +00001090 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001091 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));
niklase@google.com470e71d2011-07-07 08:21:25 +00001099 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001100
Sam Zackrisson41478c72019-10-15 10:10:26 +02001101 // 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));
niklase@google.com470e71d2011-07-07 08:21:25 +00001107 }
1108
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001109 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001110 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));
niklase@google.com470e71d2011-07-07 08:21:25 +00001115 }
1116
1117 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001118 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 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001124
Hanna Silencd597042021-11-02 11:02:48 +01001125 // 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));
niklase@google.com470e71d2011-07-07 08:21:25 +00001134}
1135
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001136#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001137using ApmDeathTest = ApmTest;
1138
1139TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001140 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001141 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001142 config.gain_controller1.target_level_dbfs = -1;
1143 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001144}
1145
Tommia5e07cc2020-05-26 21:40:37 +02001146TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001147 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001148 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001149 config.gain_controller1.target_level_dbfs = 32;
1150 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001151}
1152
Tommia5e07cc2020-05-26 21:40:37 +02001153TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001154 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001155 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001156 config.gain_controller1.compression_gain_db = -1;
1157 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001158}
1159
Tommia5e07cc2020-05-26 21:40:37 +02001160TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001161 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001162 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001163 config.gain_controller1.compression_gain_db = 91;
1164 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001165}
1166
Tommia5e07cc2020-05-26 21:40:37 +02001167TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001168 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001169 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001170 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001171 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001172}
1173
Tommia5e07cc2020-05-26 21:40:37 +02001174TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001175 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001176 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001177 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001178 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001179}
1180#endif
1181
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001182void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001183 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001184 auto config = apm_->GetConfig();
1185 config.gain_controller1.enabled = true;
1186 config.gain_controller1.mode =
1187 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1188 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001189
1190 int out_analog_level = 0;
1191 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001192 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001193 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001194 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001195
1196 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001197 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001198 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001203 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001204 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001205 }
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.
1213TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001214 for (size_t sample_rate_hz : kProcessSampleRates) {
1215 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1216 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001217 }
1218}
1219
1220void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001221 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001222 auto config = apm_->GetConfig();
1223 config.gain_controller1.enabled = true;
1224 config.gain_controller1.mode =
1225 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1226 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001227
1228 int out_analog_level = 100;
1229 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001230 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001231 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001232 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001233
Sam Zackrisson41478c72019-10-15 10:10:26 +02001234 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001235 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001240 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001241 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001242 }
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) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001251 ReadFrameWithRewind(near_file_, &frame_);
1252 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001253
Sam Zackrisson41478c72019-10-15 10:10:26 +02001254 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001255 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001260 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001261 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001262 // 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
1269TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001270 for (size_t sample_rate_hz : kProcessSampleRates) {
1271 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1272 RunManualVolumeChangeIsPossibleTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001273 }
1274}
1275
niklase@google.com470e71d2011-07-07 08:21:25 +00001276TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001277 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001278 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);
niklase@google.com470e71d2011-07-07 08:21:25 +00001283}
1284
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001285TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001286 AudioProcessing::Config config = apm_->GetConfig();
1287 EXPECT_FALSE(config.echo_canceller.enabled);
1288 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001289 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001290 EXPECT_FALSE(config.noise_suppression.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001291}
1292
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001293TEST_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);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001305 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001306 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001307 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001308 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001309 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001314 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001315 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001316 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()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001322 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001323 }
1324 }
1325}
1326
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001327TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001328 // Test that ProcessStream simply copies input to output when all components
1329 // are disabled.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001330 const size_t kSamples = 160;
1331 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001332 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001333 float dest[kSamples] = {};
1334
1335 auto src_channels = &src[0];
1336 auto dest_channels = &dest[0];
1337
Niels Möller4f776ac2021-07-02 11:30:54 +02001338 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001339 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1340 StreamConfig(sample_rate, 1),
1341 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001342
1343 for (size_t i = 0; i < kSamples; ++i) {
1344 EXPECT_EQ(src[i], dest[i]);
1345 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001346
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 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001359}
1360
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001361TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1362 EnableAllComponents();
1363
pkasting25702cb2016-01-08 13:50:27 -08001364 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001365 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1366 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001367 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001368 ASSERT_EQ(0, feof(far_file_));
1369 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001370 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001371 CopyLeftToRightChannel(revframe_.data.data(),
1372 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001373
Per Åhgren2507f8c2020-03-19 12:33:29 +01001374 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()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001381
Per Åhgren2507f8c2020-03-19 12:33:29 +01001382 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001383
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001384 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001385 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001386 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001391 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001392 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001393
Per Åhgren2507f8c2020-03-19 12:33:29 +01001394 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001395 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001396 rewind(far_file_);
1397 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001398 }
1399}
1400
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001401TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001402 // Verify the filter is not active through undistorted audio when:
1403 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001404 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001405 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001406 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001407 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001412 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001413 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001418 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001419 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001420
1421 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001422 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001423 SetFrameTo(&frame_, 1000);
1424 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001425 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001426 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001431 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001432 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001437 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001438 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001439 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001440
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001441 // Check the test is valid. We should have distortion from the filter
1442 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001443 apm_config.echo_canceller.enabled = true;
1444 apm_config.echo_canceller.mobile_mode = false;
1445 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001446 frame_.samples_per_channel = 320;
1447 frame_.num_channels = 2;
1448 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001449 SetFrameTo(&frame_, 1000);
1450 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001451 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001452 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001457 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001458 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001459}
1460
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001461#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
Ali Tofighf3592cb2022-08-16 14:44:38 +02001462void ApmTest::ProcessDebugDump(absl::string_view in_filename,
1463 absl::string_view out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001464 Format format,
1465 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001466 TaskQueueForTest worker_queue("ApmTest_worker_queue");
Ali Tofighf3592cb2022-08-16 14:44:38 +02001467 FILE* in_file = fopen(std::string(in_filename).c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001468 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 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001479 int output_sample_rate = msg.sample_rate();
1480 if (msg.has_output_sample_rate()) {
1481 output_sample_rate = msg.output_sample_rate();
1482 }
1483
Jonas Olssona4d87372019-07-05 19:08:33 +02001484 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);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001487 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001488 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001489 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001490 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));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001494 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) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001501 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001502 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001503 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001504 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1505 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001506 }
1507 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001508 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001509 if (format == kFloatFormat) {
1510 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001511 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001512 }
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.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001519 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001520
Sam Zackrisson41478c72019-10-15 10:10:26 +02001521 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001522 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001523 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) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001530 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001531 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001532 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001533 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1534 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001535 }
1536 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001537 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001538 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001539 if (format == kFloatFormat) {
1540 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001541 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001542 }
1543 }
1544 ProcessStreamChooser(format);
1545 }
1546 }
aleloif4dd1912017-06-15 01:55:38 -07001547 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001548 fclose(in_file);
1549}
1550
1551void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001552 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001553 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001554 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 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001563 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");
ivocd66b44d2016-01-15 03:06:36 -08001567 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;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001572 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001573 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);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001576
1577 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1578 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001579 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001580 ASSERT_TRUE(ref_file != NULL);
1581 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001582 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001583 std::unique_ptr<uint8_t[]> ref_bytes;
1584 std::unique_ptr<uint8_t[]> out_bytes;
1585 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001586
1587 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1588 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001589 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001590 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001591 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001592 while (ref_size > 0 && out_size > 0) {
1593 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001594 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001595 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001596 EXPECT_GE(ref_size, limited_size);
Alessio Bazzica85a126e2022-08-11 15:48:54 +02001597 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 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001604 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1605 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001606 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001607 }
1608 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001609 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1610 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001611 EXPECT_NE(0, feof(ref_file));
1612 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001613 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001614 ASSERT_EQ(0, fclose(ref_file));
1615 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001616 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001617 remove(ref_filename.c_str());
1618 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001619 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001620}
1621
pbosc7a65692016-05-06 12:50:04 -07001622TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001623 VerifyDebugDumpTest(kIntFormat);
1624}
1625
pbosc7a65692016-05-06 12:50:04 -07001626TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001627 VerifyDebugDumpTest(kFloatFormat);
1628}
1629#endif
1630
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001631// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001632TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001633 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001634 const std::string filename =
1635 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001636 {
1637 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1638 EXPECT_FALSE(aec_dump);
1639 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001640
1641#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1642 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001643 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001644
aleloif4dd1912017-06-15 01:55:38 -07001645 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1646 EXPECT_TRUE(aec_dump);
1647 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001648 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001653 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001654 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()));
aleloif4dd1912017-06-15 01:55:38 -07001660 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001661
1662 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001663 FILE* fid = fopen(filename.c_str(), "r");
1664 ASSERT_TRUE(fid != NULL);
1665
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001666 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001667 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001668 ASSERT_EQ(0, remove(filename.c_str()));
1669#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001670 // Verify the file has NOT been written.
1671 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1672#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1673}
1674
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001675// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001676TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001677 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001678
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001679 const std::string filename =
1680 test::TempFilename(test::OutputPath(), "debug_aec");
Ali Tofigh2ab914c2022-04-13 12:55:15 +02001681 FileWrapper f = FileWrapper::OpenWriteOnly(filename);
Niels Möllere8e4dc42019-06-11 14:04:16 +02001682 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001683
1684#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1685 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001686 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001687
Niels Möllere8e4dc42019-06-11 14:04:16 +02001688 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001689 EXPECT_TRUE(aec_dump);
1690 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001691 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001702 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001703 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001704
1705 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001706 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001707 ASSERT_TRUE(fid != NULL);
1708
1709 // Clean it up.
1710 ASSERT_EQ(0, fclose(fid));
1711 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001712#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1713}
1714
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001715// TODO(andrew): Add a test to process a few frames with different combinations
1716// of enabled components.
1717
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001718TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001719 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001720 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001721
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001722 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001723 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001724 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001725 const int kChannels[] = {1, 2};
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001726 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001727 for (size_t i = 0; i < arraysize(kChannels); i++) {
1728 for (size_t j = 0; j < arraysize(kChannels); j++) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001729 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001730 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001731 test->set_num_reverse_channels(kChannels[i]);
1732 test->set_num_input_channels(kChannels[j]);
1733 test->set_num_output_channels(kChannels[j]);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001734 test->set_sample_rate(sample_rate_hz);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001735 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001736 }
1737 }
1738 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001739#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
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001748 }
1749
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001750 for (int i = 0; i < ref_data.test_size(); i++) {
1751 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001752
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001753 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001754 // 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
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01001759 apm_ = AudioProcessingBuilderForTesting()
1760 .SetEchoDetector(CreateEchoDetector())
1761 .Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001762 AudioProcessing::Config apm_config = apm_->GetConfig();
1763 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1764 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001765
1766 EnableAllComponents();
1767
Jonas Olssona4d87372019-07-05 19:08:33 +02001768 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001769 static_cast<size_t>(test->num_input_channels()),
1770 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001771 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001772
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001773 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001774 int analog_level = 127;
1775 int analog_level_average = 0;
1776 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001777#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001778 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001779#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001780
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001781 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001782 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()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001789
1790 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001791 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001792
Per Åhgren2507f8c2020-03-19 12:33:29 +01001793 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001798 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001799
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001800 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001801 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001802 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001803
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001804 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001805
Sam Zackrisson41478c72019-10-15 10:10:26 +02001806 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001807 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001808 AudioProcessingStats stats = apm_->GetStatistics();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001809
Per Åhgren2507f8c2020-03-19 12:33:29 +01001810 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001811 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001812 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001813 ASSERT_EQ(frame_size, write_count);
1814
1815 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001816 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001817 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001818
1819#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1820 const int kStatsAggregationFrameNum = 100; // 1 second.
1821 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001822 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001823 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001824
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001825 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001826 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001827 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001828 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001829 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001830 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001831 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001832 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001833
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001834 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001835 const audioproc::Test::EchoMetrics& reference =
1836 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001837 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);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001841 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);
minyue58530ed2016-05-24 05:50:12 -07001846 ++stats_index;
1847 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001848 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);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001852 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1853 message_echo->set_residual_echo_likelihood_recent_max(
1854 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001855 }
1856 }
1857#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001858 }
1859 max_output_average /= frame_count;
1860 analog_level_average /= frame_count;
1861
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001862 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001863 const int kIntNear = 1;
Alessio Bazzica1db0a262022-02-15 14:18:09 +00001864 // All numbers being consistently higher on N7 compare to the reference
1865 // data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001866 // 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.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001869#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001870 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001871 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001872#else
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001873 const int kMaxOutputAverageOffset = 0;
1874 const int kMaxOutputAverageNear = kIntNear;
1875#endif
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001876 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001877 EXPECT_NEAR(test->max_output_average(),
1878 max_output_average - kMaxOutputAverageOffset,
1879 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001880 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001881 test->set_analog_level_average(analog_level_average);
1882 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001883 }
1884
1885 rewind(far_file_);
1886 rewind(near_file_);
1887 }
1888
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001889 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001890 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001891 }
1892}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001893
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001894// 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.
1897void UpdateBestSNR(const float* ref,
1898 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001899 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001900 int expected_delay,
1901 double* variance_acc,
1902 double* sq_error_acc) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001903 RTC_CHECK_LT(expected_delay, length)
1904 << "delay greater than signal length, cannot compute SNR";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001905 double best_snr = std::numeric_limits<double>::min();
1906 double best_variance = 0;
1907 double best_sq_error = 0;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001908 // Search over a region of nine samples around the expected delay.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001909 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1910 ++delay) {
1911 double sq_error = 0;
1912 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001913 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001914 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.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001947typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001948class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001949 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001950 public:
1951 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001952 : 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())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001958
1959 virtual ~AudioProcessingTest() {}
1960
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001961 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001962 // Create all needed output reference files.
Peter Kasting69558702016-01-12 16:26:35 -08001963 const size_t kNumChannels[] = {1, 2};
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001964 for (size_t i = 0; i < arraysize(kProcessSampleRates); ++i) {
pkasting25702cb2016-01-08 13:50:27 -08001965 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1966 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001967 // The reference files always have matching input and output channels.
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001968 ProcessFormat(kProcessSampleRates[i], kProcessSampleRates[i],
1969 kProcessSampleRates[i], kProcessSampleRates[i],
1970 kNumChannels[j], kNumChannels[j], kNumChannels[k],
1971 kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001972 }
1973 }
1974 }
1975 }
1976
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001977 void TearDown() {
1978 // Remove "out" files after each test.
1979 ClearTempOutFiles();
1980 }
1981
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001982 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001983
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001984 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02001985 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07001986 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001987 static void ProcessFormat(int input_rate,
1988 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001989 int reverse_input_rate,
1990 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001991 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,
Ali Tofighf3592cb2022-08-16 14:44:38 +02001995 absl::string_view output_file_prefix) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001996 AudioProcessing::Config apm_config;
Per Åhgren0695df12020-01-13 14:43:13 +01001997 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001998 rtc::scoped_refptr<AudioProcessing> ap =
1999 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren0695df12020-01-13 14:43:13 +01002000
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002001 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002002
ekmeyerson60d9b332015-08-14 10:35:55 -07002003 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");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002012 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02002013 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");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002027 ASSERT_TRUE(far_file != NULL);
2028 ASSERT_TRUE(near_file != NULL);
2029 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002030 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002031
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002032 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002033 num_input_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002034 ChannelBuffer<float> rev_cb(
2035 AudioProcessing::GetFrameSize(reverse_input_rate),
2036 num_reverse_input_channels);
2037 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002038 num_output_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002039 ChannelBuffer<float> rev_out_cb(
2040 AudioProcessing::GetFrameSize(reverse_output_rate),
2041 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002042
2043 // Temporary buffers.
2044 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002045 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()));
kwiberg62eaacf2016-02-17 06:39:05 -08002047 std::unique_ptr<float[]> float_data(new float[max_length]);
2048 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002049
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)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002053 EXPECT_NOERR(ap->ProcessReverseStream(
2054 rev_cb.channels(), processing_config.reverse_input_stream(),
2055 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002056
2057 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002058 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002059
2060 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002061 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2062 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002063
ekmeyerson60d9b332015-08-14 10:35:55 -07002064 // Dump forward output to file.
2065 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002066 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002067 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002068
Jonas Olssona4d87372019-07-05 19:08:33 +02002069 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2070 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002071
ekmeyerson60d9b332015-08-14 10:35:55 -07002072 // 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());
pkasting25702cb2016-01-08 13:50:27 -08002075 size_t rev_out_length =
2076 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002077
Jonas Olssona4d87372019-07-05 19:08:33 +02002078 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2079 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002080
Sam Zackrisson41478c72019-10-15 10:10:26 +02002081 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002082 }
2083 fclose(far_file);
2084 fclose(near_file);
2085 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002086 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002087 }
2088
2089 protected:
2090 int input_rate_;
2091 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002092 int reverse_input_rate_;
2093 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002094 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002095 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002096};
2097
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002098TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002099 struct ChannelFormat {
2100 int num_input;
2101 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002102 int num_reverse_input;
2103 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002104 };
2105 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002106 {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},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002108 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002109
pkasting25702cb2016-01-08 13:50:27 -08002110 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002111 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");
Alejandro Luebs47748742015-05-22 12:00:21 -07002114
ekmeyerson60d9b332015-08-14 10:35:55 -07002115 // 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;
ekmeyerson60d9b332015-08-14 10:35:55 -07002129 if (min_ref_rate > 32000) {
2130 ref_rate = 48000;
2131 } else if (min_ref_rate > 16000) {
2132 ref_rate = 32000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002133 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002134 ref_rate = 16000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002135 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002136
ekmeyerson60d9b332015-08-14 10:35:55 -07002137 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,
Jonas Olssona4d87372019-07-05 19:08:33 +02002141 cf[i].num_reverse_output, file_direction)
2142 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002143 "rb");
2144 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002145 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");
ekmeyerson60d9b332015-08-14 10:35:55 -07002152 ASSERT_TRUE(out_file != NULL);
2153 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002154
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002155 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;
ekmeyerson60d9b332015-08-14 10:35:55 -07002159 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002160 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002161 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002162 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002163 // Data from the resampled output, in case the reference and output rates
2164 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002165 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002166
ekmeyerson60d9b332015-08-14 10:35:55 -07002167 PushResampler<float> resampler;
2168 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002169
ekmeyerson60d9b332015-08-14 10:35:55 -07002170 // 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 }
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002187 // The delay is multiplied by the number of channels because
2188 // UpdateBestSNR() computes the SNR over interleaved data without taking
2189 // channels into account.
ekmeyerson60d9b332015-08-14 10:35:55 -07002190 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002191 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002192
ekmeyerson60d9b332015-08-14 10:35:55 -07002193 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
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002200 // necessary.
pkasting25702cb2016-01-08 13:50:27 -08002201 ASSERT_EQ(ref_length,
2202 static_cast<size_t>(resampler.Resample(
2203 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002204 out_ptr = cmp_data.get();
2205 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002206
Artem Titov0b489302021-07-28 20:50:03 +02002207 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002208 // SNR of reference vs output.
2209 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2210 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002211 }
2212
ekmeyerson60d9b332015-08-14 10:35:55 -07002213 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 {
aluebs776593b2016-03-15 14:04:58 -07002224 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002225 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002226
ekmeyerson60d9b332015-08-14 10:35:55 -07002227 fclose(out_file);
2228 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002229 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002230 }
2231}
2232
2233#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002234INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002235 CommonFormats,
2236 AudioProcessingTest,
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002237 // Internal processing rates and the particularly common sample rate 44100
2238 // Hz are tested in a grid of combinations (capture in, render in, out).
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002239 ::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),
Alejandro Luebs47748742015-05-22 12:00:21 -07002251
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002252 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),
Alejandro Luebs47748742015-05-22 12:00:21 -07002264
Per Åhgrenc0424252019-12-10 13:04:15 +01002265 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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002268 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),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002273 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002274 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),
Alejandro Luebs47748742015-05-22 12:00:21 -07002277
Per Åhgrenc0424252019-12-10 13:04:15 +01002278 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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002281 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),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002288 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002289 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)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002304
2305#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002306INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002307 CommonFormats,
2308 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002309 ::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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002312 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),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002315 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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002318 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),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002321
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002322 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),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002328 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),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002334
Per Åhgrenc0424252019-12-10 13:04:15 +01002335 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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002338 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),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002341 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002342 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002343 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002344 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),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002347
Per Åhgrenc0424252019-12-10 13:04:15 +01002348 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),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002351 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),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002354 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002355 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002356 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002357 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2358 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002359 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)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002366#endif
2367
Per Åhgren3e8bf282019-08-29 23:38:40 +02002368// Produces a scoped trace debug output.
2369std::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:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002379 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002380 << render_input_sample_rate_hz
2381 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002382 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002383 << render_output_sample_rate_hz
2384 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002385 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002386 << capture_input_sample_rate_hz
2387 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002388 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002389 << capture_output_sample_rate_hz
2390 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002391 "\nNumber of channels:"
2392 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002393 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002394 << "\n Render output: " << render_output_num_channels
2395 << "\n Capture input: " << capture_input_num_channels
2396 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002397 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.
2402void 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) {
Per Åhgren3e8bf282019-08-29 23:38:40 +02002406 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002407 apm_config.pipeline.multi_channel_render = true;
2408 apm_config.pipeline.multi_channel_capture = true;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002409 apm_config.echo_canceller.enabled = true;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002410 rtc::scoped_refptr<AudioProcessing> apm =
2411 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002412
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);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002442
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002443 size_t max_frame_size =
2444 AudioProcessing::GetFrameSize(sample_rate_hz);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002445 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
Alessio Bazzica3438a932020-10-14 12:47:50 +02002495constexpr void Toggle(bool& b) {
2496 b ^= true;
2497}
2498
niklase@google.com470e71d2011-07-07 08:21:25 +00002499} // namespace
peahc19f3122016-10-07 14:54:10 -07002500
Alessio Bazzicac054e782018-04-16 12:10:09 +02002501TEST(RuntimeSettingTest, TestDefaultCtor) {
2502 auto s = AudioProcessing::RuntimeSetting();
2503 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2504}
2505
Alessio Bazzicac054e782018-04-16 12:10:09 +02002506TEST(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
Sam Zackrisson0beac582017-09-25 12:04:02 +02002514TEST(ApmConfiguration, EnablePostProcessing) {
2515 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002516 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002517 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002518 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002519 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002520 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002521 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002522 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002523 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002524
Per Åhgren2507f8c2020-03-19 12:33:29 +01002525 Int16FrameData audio;
2526 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002527 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2528
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002529 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002530 apm->ProcessStream(audio.data.data(),
2531 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2532 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002533 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002534}
2535
Alex Loiko5825aa62017-12-18 16:02:40 +01002536TEST(ApmConfiguration, EnablePreProcessing) {
2537 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002538 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002539 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002540 auto mock_pre_processor =
2541 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002542 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002543 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002544 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002545 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002546
Per Åhgren2507f8c2020-03-19 12:33:29 +01002547 Int16FrameData audio;
2548 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002549 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2550
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002551 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002552 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());
Alex Loiko5825aa62017-12-18 16:02:40 +01002556}
2557
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002558TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2559 // Verify that apm uses a capture analyzer if one is provided.
2560 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002561 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002562 auto mock_capture_analyzer =
2563 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2564 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002565 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002566 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2567 .Create();
2568
Per Åhgren2507f8c2020-03-19 12:33:29 +01002569 Int16FrameData audio;
2570 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002571 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2572
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002573 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002574 apm->ProcessStream(audio.data.data(),
2575 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2576 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002577 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002578}
2579
Alex Loiko73ec0192018-05-15 10:52:28 +02002580TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2581 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002582 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002583 auto mock_pre_processor =
2584 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2585 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002586 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002587 .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.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002594 Int16FrameData audio;
2595 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002596 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2597
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002598 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2599 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002600 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());
Alex Loiko73ec0192018-05-15 10:52:28 +02002604}
2605
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002606class MyEchoControlFactory : public EchoControlFactory {
2607 public:
2608 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2609 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002610 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2611 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002612 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2613 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002614 return std::unique_ptr<EchoControl>(ec);
2615 }
Per Åhgrence202a02019-09-02 17:01:19 +02002616
2617 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002618 int num_render_channels,
2619 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002620 return Create(sample_rate_hz);
2621 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002622};
2623
2624TEST(ApmConfiguration, EchoControlInjection) {
2625 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002626 std::unique_ptr<EchoControlFactory> echo_control_factory(
2627 new MyEchoControlFactory());
2628
Alex Loiko5825aa62017-12-18 16:02:40 +01002629 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002630 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002631 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002632 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002633
Per Åhgren2507f8c2020-03-19 12:33:29 +01002634 Int16FrameData audio;
2635 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002636 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002637 apm->ProcessStream(audio.data.data(),
2638 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2639 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002640 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002641 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002648 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002649}
Ivo Creusenae026092017-11-20 13:07:16 +01002650
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002651TEST(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);
Niels Möller4f776ac2021-07-02 11:30:54 +02002659 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002660 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
2714rtc::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();
Ivo Creusenae026092017-11-20 13:07:16 +01002720 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
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002731 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002732 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002733 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002734 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002735 apm_config.gain_controller2.enabled = false;
2736 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002737 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002738 apm_config.noise_suppression.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002739 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002740 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
Per Åhgren8607f842019-04-12 22:02:26 +02002749TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2750 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002751 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002752 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002753 AudioProcessing::Config apm_config;
2754 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002755 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002756
2757 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002758 Int16FrameData frame;
2759 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002760 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002761
2762 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002763 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002764 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++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002770 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);
Ivo Creusenae026092017-11-20 13:07:16 +01002776 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002777 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002781 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002782 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002783 }
2784
2785 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002786 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002787 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002788 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002789 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2790 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002791 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002792 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2793 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002794 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002795 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002796 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002797 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002798}
2799
2800TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2801 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002802 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002803 ASSERT_TRUE(apm);
2804
2805 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002806 Int16FrameData frame;
2807 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002808 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002809
2810 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002811 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002812 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++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002818 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);
Ivo Creusenae026092017-11-20 13:07:16 +01002824 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002825 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002829 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002830 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002831 }
2832
2833 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002834 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002835 // We expect only the residual echo detector statistics to be set and have a
2836 // sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002837 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());
Ivo Creusenae026092017-11-20 13:07:16 +01002845}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002846
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002847TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002848 ProcessingConfig processing_config = {
2849 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002850
2851 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002852 Int16FrameData frame;
2853 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002854 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2855
2856 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002857 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002858 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2859 ptr[i] = 10000 * ((i % 3) - 1);
2860 }
2861
Niels Möller4f776ac2021-07-02 11:30:54 +02002862 rtc::scoped_refptr<AudioProcessing> apm =
2863 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002864 apm->Initialize(processing_config);
2865
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002866 // No metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002867 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002871 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002872 0);
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002873 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002874}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002875
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002876TEST(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
2894TEST(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
Per Åhgren3e8bf282019-08-29 23:38:40 +02002915TEST(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
2923TEST(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
2931TEST(ApmConfiguration, HandlingOfRateCombinations) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002932 // 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};
Per Åhgren3e8bf282019-08-29 23:38:40 +02002939 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
Yves Gerey1fce3f82019-12-05 17:45:31 +01002945TEST(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
Alessio Bazzica3438a932020-10-14 12:47:50 +02002954TEST(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
Alessio Bazzica3438a932020-10-14 12:47:50 +02002979 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
Alessio Bazzica3438a932020-10-14 12:47:50 +02002994 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.
3001TEST(AudioProcessing, GainController1ConfigNotEqual) {
3002 AudioProcessing::Config::GainController1 a;
3003 const AudioProcessing::Config::GainController1 b;
3004
3005 Toggle(a.enabled);
3006 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003007 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003008
3009 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
3010 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003011 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003012
3013 a.target_level_dbfs++;
3014 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003015 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003016
3017 a.compression_gain_db++;
3018 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003019 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003020
3021 Toggle(a.enable_limiter);
3022 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003023 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003024
Alessio Bazzica3438a932020-10-14 12:47:50 +02003025 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);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003030 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003031
3032 a_analog.startup_min_volume++;
3033 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003034 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003035
3036 a_analog.clipped_level_min++;
3037 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003038 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003039
Alessio Bazzica3438a932020-10-14 12:47:50 +02003040 Toggle(a_analog.enable_digital_adaptive);
3041 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003042 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003043}
3044
3045TEST(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
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003054 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003055 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
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003065 Toggle(a_adaptive.dry_run);
3066 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003067 EXPECT_EQ(a, b);
3068
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003069 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
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003081 a_adaptive.vad_reset_period_ms++;
3082 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003083 EXPECT_EQ(a, b);
3084
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003085 a_adaptive.adjacent_speech_frames_threshold++;
3086 b_adaptive.adjacent_speech_frames_threshold =
3087 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003088 EXPECT_EQ(a, b);
3089
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003090 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003091 b_adaptive.max_gain_change_db_per_second =
3092 a_adaptive.max_gain_change_db_per_second;
3093 EXPECT_EQ(a, b);
3094
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003095 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003096 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.
3103TEST(AudioProcessing, GainController2ConfigNotEqual) {
3104 AudioProcessing::Config::GainController2 a;
3105 const AudioProcessing::Config::GainController2 b;
3106
3107 Toggle(a.enabled);
3108 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003109 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003110
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003111 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003112 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003113 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003114
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);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003120 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003121
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003122 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003123 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003124 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003125
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003126 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
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003138 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003139 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003140 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003141
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003142 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003143 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003144 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003145
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003146 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003147 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003148 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003149
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003150 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003151 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003152 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003153}
3154
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003155} // namespace webrtc