blob: 5c934338ff00c931827da1be8ffd309d99aec041 [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>
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000021
Sam Zackrisson6558fa52019-08-26 10:12:41 +020022#include "absl/flags/flag.h"
Sam Zackrisson03cb7e52021-12-06 15:40:04 +010023#include "api/audio/echo_detector_creator.h"
Niels Möller105711e2022-06-14 15:48:26 +020024#include "api/make_ref_counted.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "common_audio/include/audio_util.h"
26#include "common_audio/resampler/include/push_resampler.h"
27#include "common_audio/resampler/push_sinc_resampler.h"
28#include "common_audio/signal_processing/include/signal_processing_library.h"
29#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
30#include "modules/audio_processing/audio_processing_impl.h"
Sam Zackrisson0beac582017-09-25 12:04:02 +020031#include "modules/audio_processing/include/mock_audio_processing.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020032#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020033#include "modules/audio_processing/test/protobuf_utils.h"
34#include "modules/audio_processing/test/test_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "rtc_base/arraysize.h"
36#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080037#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020038#include "rtc_base/gtest_prod_util.h"
39#include "rtc_base/ignore_wundef.h"
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +010040#include "rtc_base/numerics/safe_conversions.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010041#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020042#include "rtc_base/protobuf_utils.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020043#include "rtc_base/strings/string_builder.h"
Alessio Bazzicac054e782018-04-16 12:10:09 +020044#include "rtc_base/swap_queue.h"
Niels Möllera12c42a2018-07-25 16:05:48 +020045#include "rtc_base/system/arch.h"
Danil Chapovalov07122bc2019-03-26 14:37:01 +010046#include "rtc_base/task_queue_for_test.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020047#include "rtc_base/thread.h"
Per Åhgrena43178c2020-09-25 12:02:32 +020048#include "system_wrappers/include/cpu_features_wrapper.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020049#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080050#include "test/testsupport/file_utils.h"
kwiberg77eab702016-09-28 17:42:01 -070051
52RTC_PUSH_IGNORING_WUNDEF()
Alessio Bazzica85a126e2022-08-11 15:48:54 +020053#include "modules/audio_processing/debug.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000054#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000055#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000056#else
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020057#include "modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000058#endif
kwiberg77eab702016-09-28 17:42:01 -070059RTC_POP_IGNORING_WUNDEF()
niklase@google.com470e71d2011-07-07 08:21:25 +000060
Sam Zackrisson6558fa52019-08-26 10:12:41 +020061ABSL_FLAG(bool,
62 write_apm_ref_data,
63 false,
64 "Write ApmTest.Process results to file, instead of comparing results "
65 "to the existing reference data file.");
66
andrew@webrtc.org27c69802014-02-18 20:24:56 +000067namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000068namespace {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000069
Sam Zackrisson3bd444f2022-08-03 14:37:00 +020070// All sample rates used by APM internally during processing. Other input /
71// output rates are resampled to / from one of these.
72const int kProcessSampleRates[] = {16000, 32000, 48000};
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000073
ekmeyerson60d9b332015-08-14 10:35:55 -070074enum StreamDirection { kForward = 0, kReverse };
75
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000076void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 19:08:33 +020077 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
78 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000079 cb_int.channels());
Peter Kasting69558702016-01-12 16:26:35 -080080 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +020081 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000082 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000083}
andrew@webrtc.org17e40642014-03-04 20:58:13 +000084
Per Åhgren2507f8c2020-03-19 12:33:29 +010085void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
86 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000087}
88
Jonas Olssona4d87372019-07-05 19:08:33 +020089void MixStereoToMono(const float* stereo,
90 float* mono,
pkasting25702cb2016-01-08 13:50:27 -080091 size_t samples_per_channel) {
92 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000093 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +000094}
95
Jonas Olssona4d87372019-07-05 19:08:33 +020096void MixStereoToMono(const int16_t* stereo,
97 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -080098 size_t samples_per_channel) {
99 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000100 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
101}
102
pkasting25702cb2016-01-08 13:50:27 -0800103void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
104 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000105 stereo[i * 2 + 1] = stereo[i * 2];
106 }
107}
108
yujo36b1a5f2017-06-12 12:45:32 -0700109void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800110 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000111 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
112 }
113}
114
Per Åhgren2507f8c2020-03-19 12:33:29 +0100115void SetFrameTo(Int16FrameData* frame, int16_t value) {
116 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700117 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100118 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000119 }
120}
121
Per Åhgren2507f8c2020-03-19 12:33:29 +0100122void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
123 ASSERT_EQ(2u, frame->num_channels);
124 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
125 frame->data[i] = left;
126 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 }
128}
129
Per Åhgren2507f8c2020-03-19 12:33:29 +0100130void ScaleFrame(Int16FrameData* frame, float scale) {
131 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700132 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100133 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000134 }
135}
136
Per Åhgren2507f8c2020-03-19 12:33:29 +0100137bool FrameDataAreEqual(const Int16FrameData& frame1,
138 const Int16FrameData& frame2) {
139 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000140 return false;
141 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100142 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000143 return false;
144 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100145 if (memcmp(
146 frame1.data.data(), frame2.data.data(),
147 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000148 return false;
149 }
150 return true;
151}
152
Per Åhgren2507f8c2020-03-19 12:33:29 +0100153rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
154 int16_t* ptr = frame->data.data();
155 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200156 return rtc::ArrayView<int16_t>(ptr, len);
157}
158
Per Åhgren2507f8c2020-03-19 12:33:29 +0100159rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
160 const int16_t* ptr = frame.data.data();
161 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200162 return rtc::ArrayView<const int16_t>(ptr, len);
163}
164
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000165void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200166 AudioProcessing::Config apm_config = ap->GetConfig();
167 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000168#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200169 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100170
171 apm_config.gain_controller1.enabled = true;
172 apm_config.gain_controller1.mode =
173 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000174#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200175 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000176
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100177 apm_config.gain_controller1.enabled = true;
178 apm_config.gain_controller1.mode =
179 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000180#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000181
saza0bad15f2019-10-16 11:46:11 +0200182 apm_config.noise_suppression.enabled = true;
183
peah8271d042016-11-22 07:24:52 -0800184 apm_config.high_pass_filter.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100185 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800186 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000187}
188
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000189// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000190template <class T>
191T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200192 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000193}
194
Per Åhgren2507f8c2020-03-19 12:33:29 +0100195int16_t MaxAudioFrame(const Int16FrameData& frame) {
196 const size_t length = frame.samples_per_channel * frame.num_channels;
197 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800198 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100199 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000200 }
201
202 return max_data;
203}
204
Alex Loiko890988c2017-08-31 10:25:48 +0200205void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700206 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000207 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000208 ASSERT_TRUE(file != NULL);
209
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100210 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000211 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800212 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000213 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000214
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000215 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000216 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200217 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000218 fclose(file);
219}
220
Alex Loiko890988c2017-08-31 10:25:48 +0200221std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200222 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000223 // Resource files are all stereo.
224 ss << name << sample_rate_hz / 1000 << "_stereo";
225 return test::ResourcePath(ss.str(), "pcm");
226}
227
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000228// Temporary filenames unique to this process. Used to be able to run these
229// tests in parallel as each process needs to be running in isolation they can't
230// have competing filenames.
231std::map<std::string, std::string> temp_filenames;
232
Alex Loiko890988c2017-08-31 10:25:48 +0200233std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000234 int input_rate,
235 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700236 int reverse_input_rate,
237 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800238 size_t num_input_channels,
239 size_t num_output_channels,
240 size_t num_reverse_input_channels,
241 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700242 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200243 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700244 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
245 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000246 if (num_output_channels == 1) {
247 ss << "mono";
248 } else if (num_output_channels == 2) {
249 ss << "stereo";
250 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100251 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000252 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700253 ss << output_rate / 1000;
254 if (num_reverse_output_channels == 1) {
255 ss << "_rmono";
256 } else if (num_reverse_output_channels == 2) {
257 ss << "_rstereo";
258 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100259 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700260 }
261 ss << reverse_output_rate / 1000;
262 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000263
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000264 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700265 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000266 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
267 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000268}
269
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000270void ClearTempFiles() {
271 for (auto& kv : temp_filenames)
272 remove(kv.second.c_str());
273}
274
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200275// Only remove "out" files. Keep "ref" files.
276void ClearTempOutFiles() {
277 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
278 const std::string& filename = it->first;
279 if (filename.substr(0, 3).compare("out") == 0) {
280 remove(it->second.c_str());
281 temp_filenames.erase(it++);
282 } else {
283 it++;
284 }
285 }
286}
287
Alex Loiko890988c2017-08-31 10:25:48 +0200288void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000289 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000290 ASSERT_TRUE(file != NULL);
291 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000292 fclose(file);
293}
294
Sam Zackrisson3bd444f2022-08-03 14:37:00 +0200295// Reads a 10 ms chunk (actually AudioProcessing::GetFrameSize() samples per
296// channel) of int16 interleaved audio from the given (assumed stereo) file,
297// converts to deinterleaved float (optionally downmixing) and returns the
298// result in `cb`. Returns false if the file ended (or on error) and true
299// otherwise.
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000300//
Artem Titov0b489302021-07-28 20:50:03 +0200301// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000302// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200303bool ReadChunk(FILE* file,
304 int16_t* int_data,
305 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000306 ChannelBuffer<float>* cb) {
307 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000308 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000309 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
310 if (read_count != frame_size) {
311 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700312 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000313 return false; // This is expected.
314 }
315
316 S16ToFloat(int_data, frame_size, float_data);
317 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000318 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000319 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200320 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000321 }
322
323 return true;
324}
325
Per Åhgrena43178c2020-09-25 12:02:32 +0200326// Returns the reference file name that matches the current CPU
327// architecture/optimizations.
328std::string GetReferenceFilename() {
329#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
330 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
331#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
332 if (GetCPUInfo(kAVX2) != 0) {
333 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
334 }
335 return test::ResourcePath("audio_processing/output_data_float", "pb");
336#endif
337}
338
Alessio Bazzica85a126e2022-08-11 15:48:54 +0200339// Flag that can temporarily be enabled for local debugging to inspect
340// `ApmTest.VerifyDebugDump(Int|Float)` failures. Do not upload code changes
341// with this flag set to true.
342constexpr bool kDumpWhenExpectMessageEqFails = false;
343
344// Checks the debug constants values used in this file so that no code change is
345// submitted with values temporarily used for local debugging.
346TEST(ApmUnitTests, CheckDebugConstants) {
347 ASSERT_FALSE(kDumpWhenExpectMessageEqFails);
348}
349
350// Expects the equality of `actual` and `expected` by inspecting a hard-coded
351// subset of `audioproc::Stream` fields.
352void ExpectStreamFieldsEq(const audioproc::Stream& actual,
353 const audioproc::Stream& expected) {
354 EXPECT_EQ(actual.input_data(), expected.input_data());
355 EXPECT_EQ(actual.output_data(), expected.output_data());
356 EXPECT_EQ(actual.delay(), expected.delay());
357 EXPECT_EQ(actual.drift(), expected.drift());
358 EXPECT_EQ(actual.level(), expected.level());
359 EXPECT_EQ(actual.keypress(), expected.keypress());
360}
361
362// Expects the equality of `actual` and `expected` by inspecting a hard-coded
363// subset of `audioproc::Event` fields.
364void ExpectEventFieldsEq(const audioproc::Event& actual,
365 const audioproc::Event& expected) {
366 EXPECT_EQ(actual.type(), expected.type());
367 if (actual.type() != expected.type()) {
368 return;
369 }
370 switch (actual.type()) {
371 case audioproc::Event::STREAM:
372 ExpectStreamFieldsEq(actual.stream(), expected.stream());
373 break;
374 default:
375 // Not implemented.
376 break;
377 }
378}
379
380// Returns true if the `actual` and `expected` byte streams share the same size
381// and contain the same data. If they differ and `kDumpWhenExpectMessageEqFails`
382// is true, checks the equality of a subset of `audioproc::Event` (nested)
383// fields.
384bool ExpectMessageEq(rtc::ArrayView<const uint8_t> actual,
385 rtc::ArrayView<const uint8_t> expected) {
386 EXPECT_EQ(actual.size(), expected.size());
387 if (actual.size() != expected.size()) {
388 return false;
389 }
390 if (memcmp(actual.data(), expected.data(), actual.size()) == 0) {
391 // Same message. No need to parse.
392 return true;
393 }
394 if (kDumpWhenExpectMessageEqFails) {
395 // Parse differing messages and expect equality to produce detailed error
396 // messages.
397 audioproc::Event event_actual, event_expected;
398 RTC_DCHECK(event_actual.ParseFromArray(actual.data(), actual.size()));
399 RTC_DCHECK(event_expected.ParseFromArray(expected.data(), expected.size()));
400 ExpectEventFieldsEq(event_actual, event_expected);
401 }
402 return false;
403}
404
niklase@google.com470e71d2011-07-07 08:21:25 +0000405class ApmTest : public ::testing::Test {
406 protected:
407 ApmTest();
408 virtual void SetUp();
409 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000410
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200411 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000412
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200413 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000414
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000415 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200416 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000417
418 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000419 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000420 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800421 size_t num_input_channels,
422 size_t num_output_channels,
423 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000424 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000425 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000426 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100427 bool ReadFrame(FILE* file, Int16FrameData* frame);
428 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
429 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200430 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100431 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000432 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200433 void ProcessDelayVerificationTest(int delay_ms,
434 int system_delay_ms,
435 int delay_min,
436 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700437 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800438 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700439 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800440 void TestChangingForwardChannels(size_t num_in_channels,
441 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700442 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800443 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700444 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000445 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
446 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000447 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000448 int ProcessStreamChooser(Format format);
449 int AnalyzeReverseStreamChooser(Format format);
450 void ProcessDebugDump(const std::string& in_filename,
451 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800452 Format format,
453 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000454 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000455
456 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000457 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200458 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100459 Int16FrameData frame_;
460 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 15:40:04 +0100461 std::unique_ptr<ChannelBuffer<float>> float_cb_;
462 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000463 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800464 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465 FILE* far_file_;
466 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000467 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000468};
469
470ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000471 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200472 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000473 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000474 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000475 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000476 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000477 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200478 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100479 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100480 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100481 apm_config.pipeline.maximum_internal_processing_rate = 48000;
482 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000483}
niklase@google.com470e71d2011-07-07 08:21:25 +0000484
485void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000486 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000487
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000488 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000489}
490
491void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000492 if (far_file_) {
493 ASSERT_EQ(0, fclose(far_file_));
494 }
495 far_file_ = NULL;
496
497 if (near_file_) {
498 ASSERT_EQ(0, fclose(near_file_));
499 }
500 near_file_ = NULL;
501
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000502 if (out_file_) {
503 ASSERT_EQ(0, fclose(out_file_));
504 }
505 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000506}
507
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000508void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200509 ASSERT_EQ(
510 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100511 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200512 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100513 {revframe_.sample_rate_hz, revframe_.num_channels},
514 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000515}
516
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000517void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000518 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000519 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800520 size_t num_input_channels,
521 size_t num_output_channels,
522 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000523 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200524 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000525 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000526 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000527
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200528 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000529 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000530 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000531
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000532 if (far_file_) {
533 ASSERT_EQ(0, fclose(far_file_));
534 }
535 std::string filename = ResourceFilePath("far", sample_rate_hz);
536 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200537 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000538
539 if (near_file_) {
540 ASSERT_EQ(0, fclose(near_file_));
541 }
542 filename = ResourceFilePath("near", sample_rate_hz);
543 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200544 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000545
546 if (open_output_file) {
547 if (out_file_) {
548 ASSERT_EQ(0, fclose(out_file_));
549 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700550 filename = OutputFilePath(
551 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
552 reverse_sample_rate_hz, num_input_channels, num_output_channels,
553 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000554 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200555 ASSERT_TRUE(out_file_ != NULL)
556 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000557 }
558}
559
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000560void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000561 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000562}
563
Jonas Olssona4d87372019-07-05 19:08:33 +0200564bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100565 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000566 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000567 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100568 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200569 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100570 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000571 if (read_count != frame_size) {
572 // Check that the file really ended.
573 EXPECT_NE(0, feof(file));
574 return false; // This is expected.
575 }
576
Per Åhgren2507f8c2020-03-19 12:33:29 +0100577 if (frame->num_channels == 1) {
578 MixStereoToMono(frame->data.data(), frame->data.data(),
579 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000580 }
581
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000582 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000583 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000584 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000585 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000586}
587
Per Åhgren2507f8c2020-03-19 12:33:29 +0100588bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000589 return ReadFrame(file, frame, NULL);
590}
591
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000592// If the end of the file has been reached, rewind it and attempt to read the
593// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200594void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100595 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000596 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200597 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000598 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200599 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000600 }
601}
602
Per Åhgren2507f8c2020-03-19 12:33:29 +0100603void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000604 ReadFrameWithRewind(file, frame, NULL);
605}
606
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000607int ApmTest::ProcessStreamChooser(Format format) {
608 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100609 return apm_->ProcessStream(
610 frame_.data.data(),
611 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
612 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100613 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000614 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200615 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100616 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100617 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100618 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200619 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000620}
621
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000622int ApmTest::AnalyzeReverseStreamChooser(Format format) {
623 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100624 return apm_->ProcessReverseStream(
625 revframe_.data.data(),
626 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
627 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
628 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000629 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000630 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100631 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100632 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000633}
634
Jonas Olssona4d87372019-07-05 19:08:33 +0200635void ApmTest::ProcessDelayVerificationTest(int delay_ms,
636 int system_delay_ms,
637 int delay_min,
638 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200639 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000640 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100641 Int16FrameData tmp_frame;
642 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000643 bool causal = true;
644
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200645 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000646 SetFrameTo(&tmp_frame, 0);
647
648 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200649 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000650 int frame_delay = delay_ms / 10;
651 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100652 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000653 frame->CopyFrom(tmp_frame);
654 frame_queue.push(frame);
655 frame_delay++;
656 causal = false;
657 }
658 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100659 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000660 frame->CopyFrom(tmp_frame);
661 frame_queue.push(frame);
662 frame_delay--;
663 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000664 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
665 // need enough frames with audio to have reliable estimates, but as few as
666 // possible to keep processing time down. 4.5 seconds seemed to be a good
667 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000668 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100669 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000670 frame->CopyFrom(tmp_frame);
671 // Use the near end recording, since that has more speech in it.
672 ASSERT_TRUE(ReadFrame(near_file_, frame));
673 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100674 Int16FrameData* reverse_frame = frame;
675 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000676 if (!causal) {
677 reverse_frame = frame_queue.front();
678 // When we call ProcessStream() the frame is modified, so we can't use the
679 // pointer directly when things are non-causal. Use an intermediate frame
680 // and copy the data.
681 process_frame = &tmp_frame;
682 process_frame->CopyFrom(*frame);
683 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100684 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
685 reverse_frame->data.data(),
686 StreamConfig(reverse_frame->sample_rate_hz,
687 reverse_frame->num_channels),
688 StreamConfig(reverse_frame->sample_rate_hz,
689 reverse_frame->num_channels),
690 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000691 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100692 EXPECT_EQ(apm_->kNoError,
693 apm_->ProcessStream(process_frame->data.data(),
694 StreamConfig(process_frame->sample_rate_hz,
695 process_frame->num_channels),
696 StreamConfig(process_frame->sample_rate_hz,
697 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100698 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000699 frame = frame_queue.front();
700 frame_queue.pop();
701 delete frame;
702
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000703 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000704 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100705 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000706 }
707 }
708
709 rewind(near_file_);
710 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100711 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000712 frame_queue.pop();
713 delete frame;
714 }
715 // Calculate expected delay estimate and acceptable regions. Further,
716 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700717 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100718 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700719 const int expected_median =
720 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
721 const int expected_median_high = rtc::SafeClamp<int>(
722 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700723 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700724 const int expected_median_low = rtc::SafeClamp<int>(
725 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700726 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000727 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100728 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200729 ASSERT_TRUE(stats.delay_median_ms.has_value());
730 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000731 EXPECT_GE(expected_median_high, median);
732 EXPECT_LE(expected_median_low, median);
733}
734
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000735void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000736 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000737 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000738
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000739 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200740 AudioProcessing::Config apm_config = apm_->GetConfig();
741 apm_config.gain_controller1.enabled = true;
742 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200743 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000744
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000745 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200746 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000747 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200748 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000749
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000750 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200751 apm_config.echo_canceller.enabled = true;
752 apm_config.echo_canceller.mobile_mode = false;
753 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000754 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200755 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200756 apm_config.gain_controller1.enabled = false;
757 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000758
759 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000760 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100761 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000762
763 // Resets after successful ProcessStream().
764 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000765 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100766 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000767
768 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200769 apm_config.gain_controller1.enabled = true;
770 apm_->ApplyConfig(apm_config);
771 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100772 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200773 apm_config.gain_controller1.enabled = false;
774 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000775
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000776 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200777 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100778 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000779
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000780 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000781 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200782 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000783 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000784}
785
786TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000787 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000788}
789
790TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000791 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000792}
793
Michael Graczyk86c6d332015-07-23 11:41:39 -0700794void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800795 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700796 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100797 frame_.num_channels = num_channels;
798
799 EXPECT_EQ(expected_return,
800 apm_->ProcessStream(
801 frame_.data.data(),
802 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
803 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100804 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100805 EXPECT_EQ(expected_return,
806 apm_->ProcessReverseStream(
807 frame_.data.data(),
808 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
809 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
810 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000811}
812
Michael Graczyk86c6d332015-07-23 11:41:39 -0700813void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800814 size_t num_in_channels,
815 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700816 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100817 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700818 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
819
820 EXPECT_EQ(expected_return,
821 apm_->ProcessStream(float_cb_->channels(), input_stream,
822 output_stream, float_cb_->channels()));
823}
824
825void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800826 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700827 AudioProcessing::Error expected_return) {
828 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100829 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700830 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100831 {frame_.sample_rate_hz, num_rev_channels},
832 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700833
ekmeyerson60d9b332015-08-14 10:35:55 -0700834 EXPECT_EQ(
835 expected_return,
836 apm_->ProcessReverseStream(
837 float_cb_->channels(), processing_config.reverse_input_stream(),
838 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700839}
840
841TEST_F(ApmTest, ChannelsInt16Interface) {
842 // Testing number of invalid and valid channels.
843 Init(16000, 16000, 16000, 4, 4, 4, false);
844
845 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
846
Peter Kasting69558702016-01-12 16:26:35 -0800847 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700848 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000849 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000850 }
851}
852
Michael Graczyk86c6d332015-07-23 11:41:39 -0700853TEST_F(ApmTest, Channels) {
854 // Testing number of invalid and valid channels.
855 Init(16000, 16000, 16000, 4, 4, 4, false);
856
857 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
858 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
859
Peter Kasting69558702016-01-12 16:26:35 -0800860 for (size_t i = 1; i < 4; ++i) {
861 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700862 // Output channels much be one or match input channels.
863 if (j == 1 || i == j) {
864 TestChangingForwardChannels(i, j, kNoErr);
865 TestChangingReverseChannels(i, kNoErr);
866
867 EXPECT_EQ(i, apm_->num_input_channels());
868 EXPECT_EQ(j, apm_->num_output_channels());
869 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800870 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700871 } else {
872 TestChangingForwardChannels(i, j,
873 AudioProcessing::kBadNumberChannelsError);
874 }
875 }
876 }
877}
878
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000879TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100880 // Testing some valid sample rates.
881 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
882 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000883 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000884 }
885}
886
Sam Zackrissone277bde2019-10-25 10:07:54 +0200887// This test repeatedly reconfigures the pre-amplifier in APM, processes a
888// number of frames, and checks that output signal has the right level.
889TEST_F(ApmTest, PreAmplifier) {
890 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200891 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100892 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200893 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100894 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200895 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
896 }
897 }
898 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100899 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200900 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200901
Per Åhgren2507f8c2020-03-19 12:33:29 +0100902 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200903 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
904 return std::accumulate(data.begin(), data.end(), 0.0f,
905 [](float a, float b) { return a + b * b; }) /
906 data.size() / 32768 / 32768;
907 };
908
909 const float input_power = compute_power(tmp_frame);
910 // Double-check that the input data is large compared to the error kEpsilon.
911 constexpr float kEpsilon = 1e-4f;
912 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
913
914 // 1. Enable pre-amp with 0 dB gain.
915 AudioProcessing::Config config = apm_->GetConfig();
916 config.pre_amplifier.enabled = true;
917 config.pre_amplifier.fixed_gain_factor = 1.0f;
918 apm_->ApplyConfig(config);
919
920 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200921 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200922 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
923 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200924 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200925 EXPECT_NEAR(output_power, input_power, kEpsilon);
926 config = apm_->GetConfig();
927 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
928
929 // 2. Change pre-amp gain via ApplyConfig.
930 config.pre_amplifier.fixed_gain_factor = 2.0f;
931 apm_->ApplyConfig(config);
932
933 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200934 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200935 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
936 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200937 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200938 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
939 config = apm_->GetConfig();
940 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
941
942 // 3. Change pre-amp gain via a RuntimeSetting.
943 apm_->SetRuntimeSetting(
944 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
945
946 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200947 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200948 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
949 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200950 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200951 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
952 config = apm_->GetConfig();
953 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
954}
955
Per Åhgrendb5d7282021-03-15 16:31:04 +0000956// This test a simple test that ensures that the emulated analog mic gain
957// functionality runs without crashing.
958TEST_F(ApmTest, AnalogMicGainEmulation) {
959 // Fill the audio frame with a sawtooth pattern.
960 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
961 const size_t samples_per_channel = frame_.samples_per_channel;
962 for (size_t i = 0; i < samples_per_channel; i++) {
963 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
964 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
965 }
966 }
967 // Cache the frame in tmp_frame.
968 Int16FrameData tmp_frame;
969 tmp_frame.CopyFrom(frame_);
970
971 // Enable the analog gain emulation.
972 AudioProcessing::Config config = apm_->GetConfig();
973 config.capture_level_adjustment.enabled = true;
974 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
975 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
976 config.gain_controller1.enabled = true;
977 config.gain_controller1.mode =
978 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
979 config.gain_controller1.analog_gain_controller.enabled = true;
980 apm_->ApplyConfig(config);
981
982 // Process a number of frames to ensure that the code runs without crashes.
983 for (int i = 0; i < 20; ++i) {
984 frame_.CopyFrom(tmp_frame);
985 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
986 }
987}
988
989// This test repeatedly reconfigures the capture level adjustment functionality
990// in APM, processes a number of frames, and checks that output signal has the
991// right level.
992TEST_F(ApmTest, CaptureLevelAdjustment) {
993 // Fill the audio frame with a sawtooth pattern.
994 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
995 const size_t samples_per_channel = frame_.samples_per_channel;
996 for (size_t i = 0; i < samples_per_channel; i++) {
997 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
998 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
999 }
1000 }
1001 // Cache the frame in tmp_frame.
1002 Int16FrameData tmp_frame;
1003 tmp_frame.CopyFrom(frame_);
1004
1005 auto compute_power = [](const Int16FrameData& frame) {
1006 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
1007 return std::accumulate(data.begin(), data.end(), 0.0f,
1008 [](float a, float b) { return a + b * b; }) /
1009 data.size() / 32768 / 32768;
1010 };
1011
1012 const float input_power = compute_power(tmp_frame);
1013 // Double-check that the input data is large compared to the error kEpsilon.
1014 constexpr float kEpsilon = 1e-20f;
1015 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
1016
1017 // 1. Enable pre-amp with 0 dB gain.
1018 AudioProcessing::Config config = apm_->GetConfig();
1019 config.capture_level_adjustment.enabled = true;
1020 config.capture_level_adjustment.pre_gain_factor = 0.5f;
1021 config.capture_level_adjustment.post_gain_factor = 4.f;
1022 const float expected_output_power1 =
1023 config.capture_level_adjustment.pre_gain_factor *
1024 config.capture_level_adjustment.pre_gain_factor *
1025 config.capture_level_adjustment.post_gain_factor *
1026 config.capture_level_adjustment.post_gain_factor * input_power;
1027 apm_->ApplyConfig(config);
1028
1029 for (int i = 0; i < 20; ++i) {
1030 frame_.CopyFrom(tmp_frame);
1031 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1032 }
1033 float output_power = compute_power(frame_);
1034 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
1035 config = apm_->GetConfig();
1036 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1037 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
1038
1039 // 2. Change pre-amp gain via ApplyConfig.
1040 config.capture_level_adjustment.pre_gain_factor = 1.0f;
1041 config.capture_level_adjustment.post_gain_factor = 2.f;
1042 const float expected_output_power2 =
1043 config.capture_level_adjustment.pre_gain_factor *
1044 config.capture_level_adjustment.pre_gain_factor *
1045 config.capture_level_adjustment.post_gain_factor *
1046 config.capture_level_adjustment.post_gain_factor * input_power;
1047 apm_->ApplyConfig(config);
1048
1049 for (int i = 0; i < 20; ++i) {
1050 frame_.CopyFrom(tmp_frame);
1051 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1052 }
1053 output_power = compute_power(frame_);
1054 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1055 config = apm_->GetConfig();
1056 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1057 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1058
1059 // 3. Change pre-amp gain via a RuntimeSetting.
1060 constexpr float kPreGain3 = 0.5f;
1061 constexpr float kPostGain3 = 3.f;
1062 const float expected_output_power3 =
1063 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1064
1065 apm_->SetRuntimeSetting(
1066 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1067 apm_->SetRuntimeSetting(
1068 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1069
1070 for (int i = 0; i < 20; ++i) {
1071 frame_.CopyFrom(tmp_frame);
1072 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1073 }
1074 output_power = compute_power(frame_);
1075 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1076 config = apm_->GetConfig();
1077 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1078 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1079}
1080
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001081TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001082 AudioProcessing::Config config = apm_->GetConfig();
1083 config.gain_controller1.enabled = false;
1084 apm_->ApplyConfig(config);
1085 config.gain_controller1.enabled = true;
1086 apm_->ApplyConfig(config);
1087
niklase@google.com470e71d2011-07-07 08:21:25 +00001088 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001089 for (auto mode :
1090 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1091 AudioProcessing::Config::GainController1::kFixedDigital,
1092 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1093 config.gain_controller1.mode = mode;
1094 apm_->ApplyConfig(config);
1095 apm_->set_stream_analog_level(100);
1096 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001097 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001098
Sam Zackrisson41478c72019-10-15 10:10:26 +02001099 // Testing target levels
1100 for (int target_level_dbfs : {0, 15, 31}) {
1101 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1102 apm_->ApplyConfig(config);
1103 apm_->set_stream_analog_level(100);
1104 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001105 }
1106
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001107 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001108 for (int compression_gain_db : {0, 10, 90}) {
1109 config.gain_controller1.compression_gain_db = compression_gain_db;
1110 apm_->ApplyConfig(config);
1111 apm_->set_stream_analog_level(100);
1112 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001113 }
1114
1115 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001116 for (bool enable : {false, true}) {
1117 config.gain_controller1.enable_limiter = enable;
1118 apm_->ApplyConfig(config);
1119 apm_->set_stream_analog_level(100);
1120 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1121 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001122
Hanna Silencd597042021-11-02 11:02:48 +01001123 // Testing level limits.
1124 constexpr int kMinLevel = 0;
1125 constexpr int kMaxLevel = 255;
1126 apm_->set_stream_analog_level(kMinLevel);
1127 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1128 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1129 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1130 apm_->set_stream_analog_level(kMaxLevel);
1131 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001132}
1133
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001134#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001135using ApmDeathTest = ApmTest;
1136
1137TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001138 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001139 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001140 config.gain_controller1.target_level_dbfs = -1;
1141 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001142}
1143
Tommia5e07cc2020-05-26 21:40:37 +02001144TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001145 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001146 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001147 config.gain_controller1.target_level_dbfs = 32;
1148 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001149}
1150
Tommia5e07cc2020-05-26 21:40:37 +02001151TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001152 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001153 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001154 config.gain_controller1.compression_gain_db = -1;
1155 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001156}
1157
Tommia5e07cc2020-05-26 21:40:37 +02001158TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001159 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001160 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001161 config.gain_controller1.compression_gain_db = 91;
1162 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001163}
1164
Tommia5e07cc2020-05-26 21:40:37 +02001165TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001166 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001167 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001168 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001169 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001170}
1171
Tommia5e07cc2020-05-26 21:40:37 +02001172TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001173 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001174 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001175 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001176 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001177}
1178#endif
1179
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001180void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001181 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001182 auto config = apm_->GetConfig();
1183 config.gain_controller1.enabled = true;
1184 config.gain_controller1.mode =
1185 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1186 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001187
1188 int out_analog_level = 0;
1189 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001190 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001191 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001192 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001193
1194 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001195 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001196 EXPECT_EQ(apm_->kNoError,
1197 apm_->ProcessStream(
1198 frame_.data.data(),
1199 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1200 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001201 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001202 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001203 }
1204
1205 // Ensure the AGC is still able to reach the maximum.
1206 EXPECT_EQ(255, out_analog_level);
1207}
1208
1209// Verifies that despite volume slider quantization, the AGC can continue to
1210// increase its volume.
1211TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001212 for (size_t sample_rate_hz : kProcessSampleRates) {
1213 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1214 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001215 }
1216}
1217
1218void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001219 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001220 auto config = apm_->GetConfig();
1221 config.gain_controller1.enabled = true;
1222 config.gain_controller1.mode =
1223 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1224 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001225
1226 int out_analog_level = 100;
1227 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001228 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001229 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001230 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001231
Sam Zackrisson41478c72019-10-15 10:10:26 +02001232 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001233 EXPECT_EQ(apm_->kNoError,
1234 apm_->ProcessStream(
1235 frame_.data.data(),
1236 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1237 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001238 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001239 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001240 }
1241
1242 // Ensure the volume was raised.
1243 EXPECT_GT(out_analog_level, 100);
1244 int highest_level_reached = out_analog_level;
1245 // Simulate a user manual volume change.
1246 out_analog_level = 100;
1247
1248 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001249 ReadFrameWithRewind(near_file_, &frame_);
1250 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001251
Sam Zackrisson41478c72019-10-15 10:10:26 +02001252 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001253 EXPECT_EQ(apm_->kNoError,
1254 apm_->ProcessStream(
1255 frame_.data.data(),
1256 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1257 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001258 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001259 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001260 // Check that AGC respected the manually adjusted volume.
1261 EXPECT_LT(out_analog_level, highest_level_reached);
1262 }
1263 // Check that the volume was still raised.
1264 EXPECT_GT(out_analog_level, 100);
1265}
1266
1267TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001268 for (size_t sample_rate_hz : kProcessSampleRates) {
1269 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1270 RunManualVolumeChangeIsPossibleTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001271 }
1272}
1273
niklase@google.com470e71d2011-07-07 08:21:25 +00001274TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001275 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001276 AudioProcessing::Config apm_config;
1277 apm_config.high_pass_filter.enabled = true;
1278 apm_->ApplyConfig(apm_config);
1279 apm_config.high_pass_filter.enabled = false;
1280 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001281}
1282
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001283TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001284 AudioProcessing::Config config = apm_->GetConfig();
1285 EXPECT_FALSE(config.echo_canceller.enabled);
1286 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001287 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001288 EXPECT_FALSE(config.noise_suppression.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001289}
1290
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001291TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledInt) {
1292 // Test that ProcessStream simply copies input to output when all components
1293 // are disabled.
1294 // Runs over all processing rates, and some particularly common or special
1295 // rates.
1296 // - 8000 Hz: lowest sample rate seen in Chrome metrics,
1297 // - 22050 Hz: APM input/output frames are not exactly 10 ms,
1298 // - 44100 Hz: very common desktop sample rate.
1299 constexpr int kSampleRatesHz[] = {8000, 16000, 22050, 32000, 44100, 48000};
1300 for (size_t sample_rate_hz : kSampleRatesHz) {
1301 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1302 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001303 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001304 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001305 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001306 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001307 EXPECT_EQ(apm_->kNoError,
1308 apm_->ProcessStream(
1309 frame_.data.data(),
1310 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1311 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001312 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001313 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001314 EXPECT_EQ(apm_->kNoError,
1315 apm_->ProcessReverseStream(
1316 frame_.data.data(),
1317 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1318 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1319 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001320 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001321 }
1322 }
1323}
1324
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001325TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001326 // Test that ProcessStream simply copies input to output when all components
1327 // are disabled.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001328 const size_t kSamples = 160;
1329 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001330 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001331 float dest[kSamples] = {};
1332
1333 auto src_channels = &src[0];
1334 auto dest_channels = &dest[0];
1335
Niels Möller4f776ac2021-07-02 11:30:54 +02001336 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001337 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1338 StreamConfig(sample_rate, 1),
1339 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001340
1341 for (size_t i = 0; i < kSamples; ++i) {
1342 EXPECT_EQ(src[i], dest[i]);
1343 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001344
1345 // Same for ProcessReverseStream.
1346 float rev_dest[kSamples] = {};
1347 auto rev_dest_channels = &rev_dest[0];
1348
1349 StreamConfig input_stream = {sample_rate, 1};
1350 StreamConfig output_stream = {sample_rate, 1};
1351 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1352 output_stream, &rev_dest_channels));
1353
1354 for (size_t i = 0; i < kSamples; ++i) {
1355 EXPECT_EQ(src[i], rev_dest[i]);
1356 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001357}
1358
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001359TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1360 EnableAllComponents();
1361
pkasting25702cb2016-01-08 13:50:27 -08001362 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001363 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1364 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001365 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001366 ASSERT_EQ(0, feof(far_file_));
1367 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001368 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001369 CopyLeftToRightChannel(revframe_.data.data(),
1370 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001371
Per Åhgren2507f8c2020-03-19 12:33:29 +01001372 ASSERT_EQ(
1373 kNoErr,
1374 apm_->ProcessReverseStream(
1375 revframe_.data.data(),
1376 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1377 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1378 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001379
Per Åhgren2507f8c2020-03-19 12:33:29 +01001380 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001381
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001382 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001383 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001384 ASSERT_EQ(kNoErr,
1385 apm_->ProcessStream(
1386 frame_.data.data(),
1387 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1388 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001389 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001390 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001391
Per Åhgren2507f8c2020-03-19 12:33:29 +01001392 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001393 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001394 rewind(far_file_);
1395 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001396 }
1397}
1398
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001399TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001400 // Verify the filter is not active through undistorted audio when:
1401 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001402 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001403 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001404 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001405 EXPECT_EQ(apm_->kNoError,
1406 apm_->ProcessStream(
1407 frame_.data.data(),
1408 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1409 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001410 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001411 EXPECT_EQ(apm_->kNoError,
1412 apm_->ProcessStream(
1413 frame_.data.data(),
1414 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1415 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001416 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001417 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001418
1419 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001420 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001421 SetFrameTo(&frame_, 1000);
1422 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001423 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001424 EXPECT_EQ(apm_->kNoError,
1425 apm_->ProcessStream(
1426 frame_.data.data(),
1427 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1428 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001429 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001430 EXPECT_EQ(apm_->kNoError,
1431 apm_->ProcessStream(
1432 frame_.data.data(),
1433 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1434 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001435 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001436 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001437 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001438
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001439 // Check the test is valid. We should have distortion from the filter
1440 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001441 apm_config.echo_canceller.enabled = true;
1442 apm_config.echo_canceller.mobile_mode = false;
1443 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001444 frame_.samples_per_channel = 320;
1445 frame_.num_channels = 2;
1446 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001447 SetFrameTo(&frame_, 1000);
1448 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001449 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001450 EXPECT_EQ(apm_->kNoError,
1451 apm_->ProcessStream(
1452 frame_.data.data(),
1453 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1454 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001455 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001456 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001457}
1458
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001459#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1460void ApmTest::ProcessDebugDump(const std::string& in_filename,
1461 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001462 Format format,
1463 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001464 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001465 FILE* in_file = fopen(in_filename.c_str(), "rb");
1466 ASSERT_TRUE(in_file != NULL);
1467 audioproc::Event event_msg;
1468 bool first_init = true;
1469
1470 while (ReadMessageFromFile(in_file, &event_msg)) {
1471 if (event_msg.type() == audioproc::Event::INIT) {
1472 const audioproc::Init msg = event_msg.init();
1473 int reverse_sample_rate = msg.sample_rate();
1474 if (msg.has_reverse_sample_rate()) {
1475 reverse_sample_rate = msg.reverse_sample_rate();
1476 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001477 int output_sample_rate = msg.sample_rate();
1478 if (msg.has_output_sample_rate()) {
1479 output_sample_rate = msg.output_sample_rate();
1480 }
1481
Jonas Olssona4d87372019-07-05 19:08:33 +02001482 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1483 msg.num_input_channels(), msg.num_output_channels(),
1484 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001485 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001486 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001487 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001488 auto aec_dump =
1489 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1490 EXPECT_TRUE(aec_dump);
1491 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001492 first_init = false;
1493 }
1494
1495 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1496 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1497
1498 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001499 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001500 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001501 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001502 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1503 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001504 }
1505 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001506 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001507 if (format == kFloatFormat) {
1508 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001509 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001510 }
1511 }
1512 AnalyzeReverseStreamChooser(format);
1513
1514 } else if (event_msg.type() == audioproc::Event::STREAM) {
1515 const audioproc::Stream msg = event_msg.stream();
1516 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001517 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001518
Sam Zackrisson41478c72019-10-15 10:10:26 +02001519 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001520 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001521 if (msg.has_keypress()) {
1522 apm_->set_stream_key_pressed(msg.keypress());
1523 } else {
1524 apm_->set_stream_key_pressed(true);
1525 }
1526
1527 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001528 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001529 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001530 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001531 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1532 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001533 }
1534 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001535 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001536 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001537 if (format == kFloatFormat) {
1538 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001539 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001540 }
1541 }
1542 ProcessStreamChooser(format);
1543 }
1544 }
aleloif4dd1912017-06-15 01:55:38 -07001545 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001546 fclose(in_file);
1547}
1548
1549void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001550 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001551 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001552 std::string format_string;
1553 switch (format) {
1554 case kIntFormat:
1555 format_string = "_int";
1556 break;
1557 case kFloatFormat:
1558 format_string = "_float";
1559 break;
1560 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001561 const std::string ref_filename = test::TempFilename(
1562 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1563 const std::string out_filename = test::TempFilename(
1564 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001565 const std::string limited_filename = test::TempFilename(
1566 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1567 const size_t logging_limit_bytes = 100000;
1568 // We expect at least this many bytes in the created logfile.
1569 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001570 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001571 ProcessDebugDump(in_filename, ref_filename, format, -1);
1572 ProcessDebugDump(ref_filename, out_filename, format, -1);
1573 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001574
1575 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1576 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001577 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001578 ASSERT_TRUE(ref_file != NULL);
1579 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001580 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001581 std::unique_ptr<uint8_t[]> ref_bytes;
1582 std::unique_ptr<uint8_t[]> out_bytes;
1583 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001584
1585 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1586 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001587 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001588 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001589 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001590 while (ref_size > 0 && out_size > 0) {
1591 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001592 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001593 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001594 EXPECT_GE(ref_size, limited_size);
Alessio Bazzica85a126e2022-08-11 15:48:54 +02001595 EXPECT_TRUE(ExpectMessageEq(/*actual=*/{out_bytes.get(), out_size},
1596 /*expected=*/{ref_bytes.get(), ref_size}));
1597 if (limited_size > 0) {
1598 EXPECT_TRUE(
1599 ExpectMessageEq(/*actual=*/{limited_bytes.get(), limited_size},
1600 /*expected=*/{ref_bytes.get(), ref_size}));
1601 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001602 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1603 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001604 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001605 }
1606 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001607 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1608 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001609 EXPECT_NE(0, feof(ref_file));
1610 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001611 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001612 ASSERT_EQ(0, fclose(ref_file));
1613 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001614 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001615 remove(ref_filename.c_str());
1616 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001617 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001618}
1619
pbosc7a65692016-05-06 12:50:04 -07001620TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001621 VerifyDebugDumpTest(kIntFormat);
1622}
1623
pbosc7a65692016-05-06 12:50:04 -07001624TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001625 VerifyDebugDumpTest(kFloatFormat);
1626}
1627#endif
1628
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001629// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001630TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001631 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001632 const std::string filename =
1633 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001634 {
1635 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1636 EXPECT_FALSE(aec_dump);
1637 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001638
1639#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1640 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001641 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001642
aleloif4dd1912017-06-15 01:55:38 -07001643 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1644 EXPECT_TRUE(aec_dump);
1645 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001646 EXPECT_EQ(apm_->kNoError,
1647 apm_->ProcessStream(
1648 frame_.data.data(),
1649 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1650 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001651 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001652 EXPECT_EQ(apm_->kNoError,
1653 apm_->ProcessReverseStream(
1654 revframe_.data.data(),
1655 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1656 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1657 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001658 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001659
1660 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001661 FILE* fid = fopen(filename.c_str(), "r");
1662 ASSERT_TRUE(fid != NULL);
1663
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001664 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001665 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001666 ASSERT_EQ(0, remove(filename.c_str()));
1667#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001668 // Verify the file has NOT been written.
1669 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1670#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1671}
1672
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001673// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001674TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001675 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001676
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001677 const std::string filename =
1678 test::TempFilename(test::OutputPath(), "debug_aec");
Ali Tofigh2ab914c2022-04-13 12:55:15 +02001679 FileWrapper f = FileWrapper::OpenWriteOnly(filename);
Niels Möllere8e4dc42019-06-11 14:04:16 +02001680 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001681
1682#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1683 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001684 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001685
Niels Möllere8e4dc42019-06-11 14:04:16 +02001686 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001687 EXPECT_TRUE(aec_dump);
1688 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001689 EXPECT_EQ(apm_->kNoError,
1690 apm_->ProcessReverseStream(
1691 revframe_.data.data(),
1692 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1693 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1694 revframe_.data.data()));
1695 EXPECT_EQ(apm_->kNoError,
1696 apm_->ProcessStream(
1697 frame_.data.data(),
1698 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1699 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001700 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001701 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001702
1703 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001704 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001705 ASSERT_TRUE(fid != NULL);
1706
1707 // Clean it up.
1708 ASSERT_EQ(0, fclose(fid));
1709 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001710#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1711}
1712
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001713// TODO(andrew): Add a test to process a few frames with different combinations
1714// of enabled components.
1715
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001716TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001717 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001718 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001719
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001720 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001721 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001722 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001723 const int kChannels[] = {1, 2};
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001724 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001725 for (size_t i = 0; i < arraysize(kChannels); i++) {
1726 for (size_t j = 0; j < arraysize(kChannels); j++) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001727 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001728 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001729 test->set_num_reverse_channels(kChannels[i]);
1730 test->set_num_input_channels(kChannels[j]);
1731 test->set_num_output_channels(kChannels[j]);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001732 test->set_sample_rate(sample_rate_hz);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001733 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001734 }
1735 }
1736 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001737#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1738 // To test the extended filter mode.
1739 audioproc::Test* test = ref_data.add_test();
1740 test->set_num_reverse_channels(2);
1741 test->set_num_input_channels(2);
1742 test->set_num_output_channels(2);
1743 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1744 test->set_use_aec_extended_filter(true);
1745#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001746 }
1747
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001748 for (int i = 0; i < ref_data.test_size(); i++) {
1749 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001750
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001751 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001752 // TODO(ajm): We no longer allow different input and output channels. Skip
1753 // these tests for now, but they should be removed from the set.
1754 if (test->num_input_channels() != test->num_output_channels())
1755 continue;
1756
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01001757 apm_ = AudioProcessingBuilderForTesting()
1758 .SetEchoDetector(CreateEchoDetector())
1759 .Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001760 AudioProcessing::Config apm_config = apm_->GetConfig();
1761 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1762 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001763
1764 EnableAllComponents();
1765
Jonas Olssona4d87372019-07-05 19:08:33 +02001766 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001767 static_cast<size_t>(test->num_input_channels()),
1768 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001769 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001770
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001771 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001772 int analog_level = 127;
1773 int analog_level_average = 0;
1774 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001775#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001776 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001777#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001778
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001779 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001780 EXPECT_EQ(
1781 apm_->kNoError,
1782 apm_->ProcessReverseStream(
1783 revframe_.data.data(),
1784 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1785 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1786 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001787
1788 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001789 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001790
Per Åhgren2507f8c2020-03-19 12:33:29 +01001791 EXPECT_EQ(apm_->kNoError,
1792 apm_->ProcessStream(
1793 frame_.data.data(),
1794 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1795 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001796 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001797
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001798 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001799 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001800 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001801
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001802 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001803
Sam Zackrisson41478c72019-10-15 10:10:26 +02001804 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001805 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001806 AudioProcessingStats stats = apm_->GetStatistics();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001807
Per Åhgren2507f8c2020-03-19 12:33:29 +01001808 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001809 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001810 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001811 ASSERT_EQ(frame_size, write_count);
1812
1813 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001814 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001815 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001816
1817#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1818 const int kStatsAggregationFrameNum = 100; // 1 second.
1819 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001820 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001821 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001822
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001823 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001824 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001825 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001826 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001827 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001828 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001829 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001830 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001831
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001832 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001833 const audioproc::Test::EchoMetrics& reference =
1834 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001835 constexpr float kEpsilon = 0.01;
1836 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1837 EXPECT_NEAR(echo_return_loss_enhancement,
1838 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001839 EXPECT_NEAR(residual_echo_likelihood,
1840 reference.residual_echo_likelihood(), kEpsilon);
1841 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1842 reference.residual_echo_likelihood_recent_max(),
1843 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001844 ++stats_index;
1845 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001846 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1847 message_echo->set_echo_return_loss(echo_return_loss);
1848 message_echo->set_echo_return_loss_enhancement(
1849 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001850 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1851 message_echo->set_residual_echo_likelihood_recent_max(
1852 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001853 }
1854 }
1855#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001856 }
1857 max_output_average /= frame_count;
1858 analog_level_average /= frame_count;
1859
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001860 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001861 const int kIntNear = 1;
Alessio Bazzica1db0a262022-02-15 14:18:09 +00001862 // All numbers being consistently higher on N7 compare to the reference
1863 // data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001864 // TODO(bjornv): If we start getting more of these offsets on Android we
1865 // should consider a different approach. Either using one slack for all,
1866 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001867#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001868 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001869 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001870#else
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001871 const int kMaxOutputAverageOffset = 0;
1872 const int kMaxOutputAverageNear = kIntNear;
1873#endif
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001874 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001875 EXPECT_NEAR(test->max_output_average(),
1876 max_output_average - kMaxOutputAverageOffset,
1877 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001878 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001879 test->set_analog_level_average(analog_level_average);
1880 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001881 }
1882
1883 rewind(far_file_);
1884 rewind(near_file_);
1885 }
1886
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001887 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001888 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001889 }
1890}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001891
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001892// Compares the reference and test arrays over a region around the expected
1893// delay. Finds the highest SNR in that region and adds the variance and squared
1894// error results to the supplied accumulators.
1895void UpdateBestSNR(const float* ref,
1896 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001897 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001898 int expected_delay,
1899 double* variance_acc,
1900 double* sq_error_acc) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001901 RTC_CHECK_LT(expected_delay, length)
1902 << "delay greater than signal length, cannot compute SNR";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001903 double best_snr = std::numeric_limits<double>::min();
1904 double best_variance = 0;
1905 double best_sq_error = 0;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001906 // Search over a region of nine samples around the expected delay.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001907 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1908 ++delay) {
1909 double sq_error = 0;
1910 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001911 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001912 double error = test[i + delay] - ref[i];
1913 sq_error += error * error;
1914 variance += ref[i] * ref[i];
1915 }
1916
1917 if (sq_error == 0) {
1918 *variance_acc += variance;
1919 return;
1920 }
1921 double snr = variance / sq_error;
1922 if (snr > best_snr) {
1923 best_snr = snr;
1924 best_variance = variance;
1925 best_sq_error = sq_error;
1926 }
1927 }
1928
1929 *variance_acc += best_variance;
1930 *sq_error_acc += best_sq_error;
1931}
1932
1933// Used to test a multitude of sample rate and channel combinations. It works
1934// by first producing a set of reference files (in SetUpTestCase) that are
1935// assumed to be correct, as the used parameters are verified by other tests
1936// in this collection. Primarily the reference files are all produced at
1937// "native" rates which do not involve any resampling.
1938
1939// Each test pass produces an output file with a particular format. The output
1940// is matched against the reference file closest to its internal processing
1941// format. If necessary the output is resampled back to its process format.
1942// Due to the resampling distortion, we don't expect identical results, but
1943// enforce SNR thresholds which vary depending on the format. 0 is a special
1944// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001945typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001946class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001947 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001948 public:
1949 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001950 : input_rate_(std::get<0>(GetParam())),
1951 output_rate_(std::get<1>(GetParam())),
1952 reverse_input_rate_(std::get<2>(GetParam())),
1953 reverse_output_rate_(std::get<3>(GetParam())),
1954 expected_snr_(std::get<4>(GetParam())),
1955 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001956
1957 virtual ~AudioProcessingTest() {}
1958
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001959 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001960 // Create all needed output reference files.
Peter Kasting69558702016-01-12 16:26:35 -08001961 const size_t kNumChannels[] = {1, 2};
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001962 for (size_t i = 0; i < arraysize(kProcessSampleRates); ++i) {
pkasting25702cb2016-01-08 13:50:27 -08001963 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1964 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001965 // The reference files always have matching input and output channels.
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001966 ProcessFormat(kProcessSampleRates[i], kProcessSampleRates[i],
1967 kProcessSampleRates[i], kProcessSampleRates[i],
1968 kNumChannels[j], kNumChannels[j], kNumChannels[k],
1969 kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001970 }
1971 }
1972 }
1973 }
1974
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001975 void TearDown() {
1976 // Remove "out" files after each test.
1977 ClearTempOutFiles();
1978 }
1979
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001980 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001981
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001982 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02001983 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07001984 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001985 static void ProcessFormat(int input_rate,
1986 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001987 int reverse_input_rate,
1988 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001989 size_t num_input_channels,
1990 size_t num_output_channels,
1991 size_t num_reverse_input_channels,
1992 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02001993 const std::string& output_file_prefix) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001994 AudioProcessing::Config apm_config;
Per Åhgren0695df12020-01-13 14:43:13 +01001995 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001996 rtc::scoped_refptr<AudioProcessing> ap =
1997 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001998
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001999 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002000
ekmeyerson60d9b332015-08-14 10:35:55 -07002001 ProcessingConfig processing_config = {
2002 {{input_rate, num_input_channels},
2003 {output_rate, num_output_channels},
2004 {reverse_input_rate, num_reverse_input_channels},
2005 {reverse_output_rate, num_reverse_output_channels}}};
2006 ap->Initialize(processing_config);
2007
2008 FILE* far_file =
2009 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002010 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02002011 FILE* out_file = fopen(
2012 OutputFilePath(
2013 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2014 reverse_output_rate, num_input_channels, num_output_channels,
2015 num_reverse_input_channels, num_reverse_output_channels, kForward)
2016 .c_str(),
2017 "wb");
2018 FILE* rev_out_file = fopen(
2019 OutputFilePath(
2020 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2021 reverse_output_rate, num_input_channels, num_output_channels,
2022 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2023 .c_str(),
2024 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002025 ASSERT_TRUE(far_file != NULL);
2026 ASSERT_TRUE(near_file != NULL);
2027 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002028 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002029
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002030 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002031 num_input_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002032 ChannelBuffer<float> rev_cb(
2033 AudioProcessing::GetFrameSize(reverse_input_rate),
2034 num_reverse_input_channels);
2035 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002036 num_output_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002037 ChannelBuffer<float> rev_out_cb(
2038 AudioProcessing::GetFrameSize(reverse_output_rate),
2039 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002040
2041 // Temporary buffers.
2042 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002043 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2044 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08002045 std::unique_ptr<float[]> float_data(new float[max_length]);
2046 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002047
2048 int analog_level = 127;
2049 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2050 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002051 EXPECT_NOERR(ap->ProcessReverseStream(
2052 rev_cb.channels(), processing_config.reverse_input_stream(),
2053 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002054
2055 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002056 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002057
2058 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002059 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2060 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002061
ekmeyerson60d9b332015-08-14 10:35:55 -07002062 // Dump forward output to file.
2063 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002064 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002065 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002066
Jonas Olssona4d87372019-07-05 19:08:33 +02002067 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2068 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002069
ekmeyerson60d9b332015-08-14 10:35:55 -07002070 // Dump reverse output to file.
2071 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2072 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002073 size_t rev_out_length =
2074 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002075
Jonas Olssona4d87372019-07-05 19:08:33 +02002076 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2077 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002078
Sam Zackrisson41478c72019-10-15 10:10:26 +02002079 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002080 }
2081 fclose(far_file);
2082 fclose(near_file);
2083 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002084 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002085 }
2086
2087 protected:
2088 int input_rate_;
2089 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002090 int reverse_input_rate_;
2091 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002092 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002093 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002094};
2095
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002096TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002097 struct ChannelFormat {
2098 int num_input;
2099 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002100 int num_reverse_input;
2101 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002102 };
2103 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002104 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2105 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002106 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002107
pkasting25702cb2016-01-08 13:50:27 -08002108 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002109 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2110 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2111 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002112
ekmeyerson60d9b332015-08-14 10:35:55 -07002113 // Verify output for both directions.
2114 std::vector<StreamDirection> stream_directions;
2115 stream_directions.push_back(kForward);
2116 stream_directions.push_back(kReverse);
2117 for (StreamDirection file_direction : stream_directions) {
2118 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2119 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2120 const int out_num =
2121 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2122 const double expected_snr =
2123 file_direction ? expected_reverse_snr_ : expected_snr_;
2124
2125 const int min_ref_rate = std::min(in_rate, out_rate);
2126 int ref_rate;
ekmeyerson60d9b332015-08-14 10:35:55 -07002127 if (min_ref_rate > 32000) {
2128 ref_rate = 48000;
2129 } else if (min_ref_rate > 16000) {
2130 ref_rate = 32000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002131 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002132 ref_rate = 16000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002133 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002134
ekmeyerson60d9b332015-08-14 10:35:55 -07002135 FILE* out_file = fopen(
2136 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2137 reverse_output_rate_, cf[i].num_input,
2138 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002139 cf[i].num_reverse_output, file_direction)
2140 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002141 "rb");
2142 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002143 FILE* ref_file =
2144 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2145 cf[i].num_output, cf[i].num_output,
2146 cf[i].num_reverse_output,
2147 cf[i].num_reverse_output, file_direction)
2148 .c_str(),
2149 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002150 ASSERT_TRUE(out_file != NULL);
2151 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002152
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002153 const size_t ref_length =
2154 AudioProcessing::GetFrameSize(ref_rate) * out_num;
2155 const size_t out_length =
2156 AudioProcessing::GetFrameSize(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002157 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002158 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002159 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002160 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002161 // Data from the resampled output, in case the reference and output rates
2162 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002163 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002164
ekmeyerson60d9b332015-08-14 10:35:55 -07002165 PushResampler<float> resampler;
2166 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002167
ekmeyerson60d9b332015-08-14 10:35:55 -07002168 // Compute the resampling delay of the output relative to the reference,
2169 // to find the region over which we should search for the best SNR.
2170 float expected_delay_sec = 0;
2171 if (in_rate != ref_rate) {
2172 // Input resampling delay.
2173 expected_delay_sec +=
2174 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2175 }
2176 if (out_rate != ref_rate) {
2177 // Output resampling delay.
2178 expected_delay_sec +=
2179 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2180 // Delay of converting the output back to its processing rate for
2181 // testing.
2182 expected_delay_sec +=
2183 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2184 }
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002185 // The delay is multiplied by the number of channels because
2186 // UpdateBestSNR() computes the SNR over interleaved data without taking
2187 // channels into account.
ekmeyerson60d9b332015-08-14 10:35:55 -07002188 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002189 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002190
ekmeyerson60d9b332015-08-14 10:35:55 -07002191 double variance = 0;
2192 double sq_error = 0;
2193 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2194 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2195 float* out_ptr = out_data.get();
2196 if (out_rate != ref_rate) {
2197 // Resample the output back to its internal processing rate if
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002198 // necessary.
pkasting25702cb2016-01-08 13:50:27 -08002199 ASSERT_EQ(ref_length,
2200 static_cast<size_t>(resampler.Resample(
2201 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002202 out_ptr = cmp_data.get();
2203 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002204
Artem Titov0b489302021-07-28 20:50:03 +02002205 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002206 // SNR of reference vs output.
2207 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2208 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002209 }
2210
ekmeyerson60d9b332015-08-14 10:35:55 -07002211 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2212 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2213 << cf[i].num_input << ", " << cf[i].num_output << ", "
2214 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2215 << ", " << file_direction << "): ";
2216 if (sq_error > 0) {
2217 double snr = 10 * log10(variance / sq_error);
2218 EXPECT_GE(snr, expected_snr);
2219 EXPECT_NE(0, expected_snr);
2220 std::cout << "SNR=" << snr << " dB" << std::endl;
2221 } else {
aluebs776593b2016-03-15 14:04:58 -07002222 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002223 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002224
ekmeyerson60d9b332015-08-14 10:35:55 -07002225 fclose(out_file);
2226 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002227 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002228 }
2229}
2230
2231#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002232INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002233 CommonFormats,
2234 AudioProcessingTest,
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002235 // Internal processing rates and the particularly common sample rate 44100
2236 // Hz are tested in a grid of combinations (capture in, render in, out).
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002237 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2238 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2239 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2240 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2241 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2242 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2243 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2244 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2245 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2246 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2247 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2248 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002249
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002250 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2251 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2252 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2253 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2254 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2255 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2256 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2257 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2258 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2259 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2260 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2261 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002262
Per Åhgrenc0424252019-12-10 13:04:15 +01002263 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2264 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2265 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002266 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2267 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2268 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2269 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2270 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002271 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002272 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2273 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2274 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002275
Per Åhgrenc0424252019-12-10 13:04:15 +01002276 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2277 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2278 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002279 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2280 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2281 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2282 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2283 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2284 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2285 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002286 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002287 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2288
2289 // Other sample rates are not tested exhaustively, to keep
2290 // the test runtime manageable.
2291 //
2292 // Testing most other sample rates logged by Chrome UMA:
2293 // - WebRTC.AudioInputSampleRate
2294 // - WebRTC.AudioOutputSampleRate
2295 // ApmConfiguration.HandlingOfRateCombinations covers
2296 // remaining sample rates.
2297 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2298 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2299 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2300 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2301 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002302
2303#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002304INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002305 CommonFormats,
2306 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002307 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2308 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2309 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002310 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2311 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2312 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002313 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2314 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2315 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002316 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2317 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2318 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002319
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002320 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2321 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2322 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2323 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2324 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2325 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002326 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2327 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2328 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2329 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2330 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2331 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002332
Per Åhgrenc0424252019-12-10 13:04:15 +01002333 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2334 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2335 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002336 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2337 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2338 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002339 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002340 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002341 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002342 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2343 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2344 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002345
Per Åhgrenc0424252019-12-10 13:04:15 +01002346 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2347 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2348 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002349 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2350 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2351 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002352 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002353 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002354 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002355 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2356 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002357 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2358
2359 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2360 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2361 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2362 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2363 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002364#endif
2365
Per Åhgren3e8bf282019-08-29 23:38:40 +02002366// Produces a scoped trace debug output.
2367std::string ProduceDebugText(int render_input_sample_rate_hz,
2368 int render_output_sample_rate_hz,
2369 int capture_input_sample_rate_hz,
2370 int capture_output_sample_rate_hz,
2371 size_t render_input_num_channels,
2372 size_t render_output_num_channels,
2373 size_t capture_input_num_channels,
2374 size_t capture_output_num_channels) {
2375 rtc::StringBuilder ss;
2376 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002377 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002378 << render_input_sample_rate_hz
2379 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002380 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002381 << render_output_sample_rate_hz
2382 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002383 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002384 << capture_input_sample_rate_hz
2385 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002386 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002387 << capture_output_sample_rate_hz
2388 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002389 "\nNumber of channels:"
2390 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002391 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002392 << "\n Render output: " << render_output_num_channels
2393 << "\n Capture input: " << capture_input_num_channels
2394 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002395 return ss.Release();
2396}
2397
2398// Validates that running the audio processing module using various combinations
2399// of sample rates and number of channels works as intended.
2400void RunApmRateAndChannelTest(
2401 rtc::ArrayView<const int> sample_rates_hz,
2402 rtc::ArrayView<const int> render_channel_counts,
2403 rtc::ArrayView<const int> capture_channel_counts) {
Per Åhgren3e8bf282019-08-29 23:38:40 +02002404 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002405 apm_config.pipeline.multi_channel_render = true;
2406 apm_config.pipeline.multi_channel_capture = true;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002407 apm_config.echo_canceller.enabled = true;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002408 rtc::scoped_refptr<AudioProcessing> apm =
2409 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002410
2411 StreamConfig render_input_stream_config;
2412 StreamConfig render_output_stream_config;
2413 StreamConfig capture_input_stream_config;
2414 StreamConfig capture_output_stream_config;
2415
2416 std::vector<float> render_input_frame_channels;
2417 std::vector<float*> render_input_frame;
2418 std::vector<float> render_output_frame_channels;
2419 std::vector<float*> render_output_frame;
2420 std::vector<float> capture_input_frame_channels;
2421 std::vector<float*> capture_input_frame;
2422 std::vector<float> capture_output_frame_channels;
2423 std::vector<float*> capture_output_frame;
2424
2425 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2426 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2427 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2428 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2429 for (size_t render_input_num_channels : render_channel_counts) {
2430 for (size_t capture_input_num_channels : capture_channel_counts) {
2431 size_t render_output_num_channels = render_input_num_channels;
2432 size_t capture_output_num_channels = capture_input_num_channels;
2433 auto populate_audio_frame = [](int sample_rate_hz,
2434 size_t num_channels,
2435 StreamConfig* cfg,
2436 std::vector<float>* channels_data,
2437 std::vector<float*>* frame_data) {
2438 cfg->set_sample_rate_hz(sample_rate_hz);
2439 cfg->set_num_channels(num_channels);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002440
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002441 size_t max_frame_size =
2442 AudioProcessing::GetFrameSize(sample_rate_hz);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002443 channels_data->resize(num_channels * max_frame_size);
2444 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2445 frame_data->resize(num_channels);
2446 for (size_t channel = 0; channel < num_channels; ++channel) {
2447 (*frame_data)[channel] =
2448 &(*channels_data)[channel * max_frame_size];
2449 }
2450 };
2451
2452 populate_audio_frame(
2453 render_input_sample_rate_hz, render_input_num_channels,
2454 &render_input_stream_config, &render_input_frame_channels,
2455 &render_input_frame);
2456 populate_audio_frame(
2457 render_output_sample_rate_hz, render_output_num_channels,
2458 &render_output_stream_config, &render_output_frame_channels,
2459 &render_output_frame);
2460 populate_audio_frame(
2461 capture_input_sample_rate_hz, capture_input_num_channels,
2462 &capture_input_stream_config, &capture_input_frame_channels,
2463 &capture_input_frame);
2464 populate_audio_frame(
2465 capture_output_sample_rate_hz, capture_output_num_channels,
2466 &capture_output_stream_config, &capture_output_frame_channels,
2467 &capture_output_frame);
2468
2469 for (size_t frame = 0; frame < 2; ++frame) {
2470 SCOPED_TRACE(ProduceDebugText(
2471 render_input_sample_rate_hz, render_output_sample_rate_hz,
2472 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2473 render_input_num_channels, render_output_num_channels,
2474 render_input_num_channels, capture_output_num_channels));
2475
2476 int result = apm->ProcessReverseStream(
2477 &render_input_frame[0], render_input_stream_config,
2478 render_output_stream_config, &render_output_frame[0]);
2479 EXPECT_EQ(result, AudioProcessing::kNoError);
2480 result = apm->ProcessStream(
2481 &capture_input_frame[0], capture_input_stream_config,
2482 capture_output_stream_config, &capture_output_frame[0]);
2483 EXPECT_EQ(result, AudioProcessing::kNoError);
2484 }
2485 }
2486 }
2487 }
2488 }
2489 }
2490 }
2491}
2492
Alessio Bazzica3438a932020-10-14 12:47:50 +02002493constexpr void Toggle(bool& b) {
2494 b ^= true;
2495}
2496
niklase@google.com470e71d2011-07-07 08:21:25 +00002497} // namespace
peahc19f3122016-10-07 14:54:10 -07002498
Alessio Bazzicac054e782018-04-16 12:10:09 +02002499TEST(RuntimeSettingTest, TestDefaultCtor) {
2500 auto s = AudioProcessing::RuntimeSetting();
2501 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2502}
2503
Alessio Bazzicac054e782018-04-16 12:10:09 +02002504TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2505 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2506 auto s = AudioProcessing::RuntimeSetting();
2507 ASSERT_TRUE(q.Insert(&s));
2508 ASSERT_TRUE(q.Remove(&s));
2509 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2510}
2511
Sam Zackrisson0beac582017-09-25 12:04:02 +02002512TEST(ApmConfiguration, EnablePostProcessing) {
2513 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002514 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002515 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002516 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002517 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002518 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002519 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002520 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002521 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002522
Per Åhgren2507f8c2020-03-19 12:33:29 +01002523 Int16FrameData audio;
2524 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002525 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2526
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002527 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002528 apm->ProcessStream(audio.data.data(),
2529 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2530 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002531 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002532}
2533
Alex Loiko5825aa62017-12-18 16:02:40 +01002534TEST(ApmConfiguration, EnablePreProcessing) {
2535 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002536 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002537 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002538 auto mock_pre_processor =
2539 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002540 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002541 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002542 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002543 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002544
Per Åhgren2507f8c2020-03-19 12:33:29 +01002545 Int16FrameData audio;
2546 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002547 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2548
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002549 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002550 apm->ProcessReverseStream(
2551 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2552 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2553 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002554}
2555
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002556TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2557 // Verify that apm uses a capture analyzer if one is provided.
2558 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002559 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002560 auto mock_capture_analyzer =
2561 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2562 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002563 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002564 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2565 .Create();
2566
Per Åhgren2507f8c2020-03-19 12:33:29 +01002567 Int16FrameData audio;
2568 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002569 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2570
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002571 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002572 apm->ProcessStream(audio.data.data(),
2573 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2574 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002575 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002576}
2577
Alex Loiko73ec0192018-05-15 10:52:28 +02002578TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2579 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002580 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002581 auto mock_pre_processor =
2582 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2583 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002584 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002585 .SetRenderPreProcessing(std::move(mock_pre_processor))
2586 .Create();
2587 apm->SetRuntimeSetting(
2588 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2589
2590 // RuntimeSettings forwarded during 'Process*Stream' calls.
2591 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002592 Int16FrameData audio;
2593 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002594 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2595
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002596 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2597 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002598 apm->ProcessReverseStream(
2599 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2600 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2601 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002602}
2603
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002604class MyEchoControlFactory : public EchoControlFactory {
2605 public:
2606 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2607 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002608 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2609 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002610 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2611 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002612 return std::unique_ptr<EchoControl>(ec);
2613 }
Per Åhgrence202a02019-09-02 17:01:19 +02002614
2615 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002616 int num_render_channels,
2617 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002618 return Create(sample_rate_hz);
2619 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002620};
2621
2622TEST(ApmConfiguration, EchoControlInjection) {
2623 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002624 std::unique_ptr<EchoControlFactory> echo_control_factory(
2625 new MyEchoControlFactory());
2626
Alex Loiko5825aa62017-12-18 16:02:40 +01002627 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002628 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002629 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002630 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002631
Per Åhgren2507f8c2020-03-19 12:33:29 +01002632 Int16FrameData audio;
2633 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002634 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002635 apm->ProcessStream(audio.data.data(),
2636 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2637 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002638 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002639 apm->ProcessReverseStream(
2640 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2641 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2642 audio.data.data());
2643 apm->ProcessStream(audio.data.data(),
2644 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2645 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002646 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002647}
Ivo Creusenae026092017-11-20 13:07:16 +01002648
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002649TEST(ApmConfiguration, EchoDetectorInjection) {
2650 using ::testing::_;
2651 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2652 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2653 EXPECT_CALL(*mock_echo_detector,
2654 Initialize(/*capture_sample_rate_hz=*/16000, _,
2655 /*render_sample_rate_hz=*/16000, _))
2656 .Times(1);
Niels Möller4f776ac2021-07-02 11:30:54 +02002657 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002658 AudioProcessingBuilderForTesting()
2659 .SetEchoDetector(mock_echo_detector)
2660 .Create();
2661
2662 // The echo detector is included in processing when enabled.
2663 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2664 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2665 EXPECT_EQ(render_audio.size(), 160u);
2666 });
2667 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2668 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2669 EXPECT_EQ(capture_audio.size(), 160u);
2670 });
2671 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2672
2673 Int16FrameData frame;
2674 frame.num_channels = 1;
2675 SetFrameSampleRate(&frame, 16000);
2676
2677 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2678 StreamConfig(16000, 1), frame.data.data());
2679 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2680 StreamConfig(16000, 1), frame.data.data());
2681
2682 // When processing rates change, the echo detector is also reinitialized to
2683 // match those.
2684 EXPECT_CALL(*mock_echo_detector,
2685 Initialize(/*capture_sample_rate_hz=*/48000, _,
2686 /*render_sample_rate_hz=*/16000, _))
2687 .Times(1);
2688 EXPECT_CALL(*mock_echo_detector,
2689 Initialize(/*capture_sample_rate_hz=*/48000, _,
2690 /*render_sample_rate_hz=*/48000, _))
2691 .Times(1);
2692 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2693 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2694 EXPECT_EQ(render_audio.size(), 480u);
2695 });
2696 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2697 .Times(2)
2698 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2699 EXPECT_EQ(capture_audio.size(), 480u);
2700 });
2701 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2702
2703 SetFrameSampleRate(&frame, 48000);
2704 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2705 StreamConfig(48000, 1), frame.data.data());
2706 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2707 StreamConfig(48000, 1), frame.data.data());
2708 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2709 StreamConfig(48000, 1), frame.data.data());
2710}
2711
2712rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2713 // Enable residual echo detection, for stats.
2714 rtc::scoped_refptr<AudioProcessing> apm =
2715 AudioProcessingBuilderForTesting()
2716 .SetEchoDetector(CreateEchoDetector())
2717 .Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002718 if (!apm) {
2719 return apm;
2720 }
2721
2722 ProcessingConfig processing_config = {
2723 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2724
2725 if (apm->Initialize(processing_config) != 0) {
2726 return nullptr;
2727 }
2728
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002729 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002730 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002731 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002732 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002733 apm_config.gain_controller2.enabled = false;
2734 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002735 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002736 apm_config.noise_suppression.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002737 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002738 return apm;
2739}
2740
2741#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2742#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2743#else
2744#define MAYBE_ApmStatistics ApmStatistics
2745#endif
2746
Per Åhgren8607f842019-04-12 22:02:26 +02002747TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2748 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002749 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002750 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002751 AudioProcessing::Config apm_config;
2752 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002753 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002754
2755 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002756 Int16FrameData frame;
2757 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002758 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002759
2760 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002761 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002762 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2763 ptr[i] = 10000 * ((i % 3) - 1);
2764 }
2765
2766 // Do some processing.
2767 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002768 EXPECT_EQ(apm->ProcessReverseStream(
2769 frame.data.data(),
2770 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2771 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2772 frame.data.data()),
2773 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002774 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002775 EXPECT_EQ(apm->ProcessStream(
2776 frame.data.data(),
2777 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2778 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002779 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002780 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002781 }
2782
2783 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002784 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002785 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002786 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002787 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2788 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002789 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002790 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2791 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002792 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002793 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002794 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002795 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002796}
2797
2798TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2799 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002800 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002801 ASSERT_TRUE(apm);
2802
2803 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002804 Int16FrameData frame;
2805 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002806 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002807
2808 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002809 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002810 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2811 ptr[i] = 10000 * ((i % 3) - 1);
2812 }
2813
2814 // Do some processing.
2815 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002816 EXPECT_EQ(apm->ProcessReverseStream(
2817 frame.data.data(),
2818 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2819 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2820 frame.data.data()),
2821 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002822 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002823 EXPECT_EQ(apm->ProcessStream(
2824 frame.data.data(),
2825 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2826 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002827 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002828 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002829 }
2830
2831 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002832 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002833 // We expect only the residual echo detector statistics to be set and have a
2834 // sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002835 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2836 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2837 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2838 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2839 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2840 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2841 EXPECT_FALSE(stats.echo_return_loss.has_value());
2842 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002843}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002844
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002845TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002846 ProcessingConfig processing_config = {
2847 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002848
2849 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002850 Int16FrameData frame;
2851 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002852 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2853
2854 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002855 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002856 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2857 ptr[i] = 10000 * ((i % 3) - 1);
2858 }
2859
Niels Möller4f776ac2021-07-02 11:30:54 +02002860 rtc::scoped_refptr<AudioProcessing> apm =
2861 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002862 apm->Initialize(processing_config);
2863
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002864 // No metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002865 EXPECT_EQ(
2866 apm->ProcessStream(frame.data.data(),
2867 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2868 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002869 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002870 0);
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002871 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002872}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002873
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002874TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2875 rtc::scoped_refptr<AudioProcessing> apm =
2876 AudioProcessingBuilderForTesting().Create();
2877 Int16FrameData frame;
2878 frame.num_channels = 1;
2879 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2880 ASSERT_EQ(
2881 apm->ProcessStream(frame.data.data(),
2882 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2883 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2884 frame.data.data()),
2885 0);
2886 // Echo detector is disabled by default, no stats reported.
2887 AudioProcessingStats stats = apm->GetStatistics();
2888 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2889 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2890}
2891
2892TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2893 // Create APM with an echo detector injected.
2894 rtc::scoped_refptr<AudioProcessing> apm =
2895 AudioProcessingBuilderForTesting()
2896 .SetEchoDetector(CreateEchoDetector())
2897 .Create();
2898 Int16FrameData frame;
2899 frame.num_channels = 1;
2900 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2901 // Echo detector enabled: Report stats.
2902 ASSERT_EQ(
2903 apm->ProcessStream(frame.data.data(),
2904 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2905 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2906 frame.data.data()),
2907 0);
2908 AudioProcessingStats stats = apm->GetStatistics();
2909 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2910 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2911}
2912
Per Åhgren3e8bf282019-08-29 23:38:40 +02002913TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2914 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2915 std::array<int, 2> render_channel_counts = {1, 7};
2916 std::array<int, 2> capture_channel_counts = {1, 7};
2917 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2918 capture_channel_counts);
2919}
2920
2921TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2922 std::array<int, 1> sample_rates_hz = {48000};
2923 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2924 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2925 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2926 capture_channel_counts);
2927}
2928
2929TEST(ApmConfiguration, HandlingOfRateCombinations) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002930 // Test rates <= 96000 logged by Chrome UMA:
2931 // - WebRTC.AudioInputSampleRate
2932 // - WebRTC.AudioOutputSampleRate
2933 // Higher rates are tested in AudioProcessingTest.Format, to keep the number
2934 // of combinations in this test manageable.
2935 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2936 44100, 48000, 88200, 96000};
Per Åhgren3e8bf282019-08-29 23:38:40 +02002937 std::array<int, 1> render_channel_counts = {2};
2938 std::array<int, 1> capture_channel_counts = {2};
2939 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2940 capture_channel_counts);
2941}
2942
Yves Gerey1fce3f82019-12-05 17:45:31 +01002943TEST(ApmConfiguration, SelfAssignment) {
2944 // At some point memory sanitizer was complaining about self-assigment.
2945 // Make sure we don't regress.
2946 AudioProcessing::Config config;
2947 AudioProcessing::Config* config2 = &config;
2948 *config2 = *config2; // Workaround -Wself-assign-overloaded
2949 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2950}
2951
Alessio Bazzica3438a932020-10-14 12:47:50 +02002952TEST(AudioProcessing, GainController1ConfigEqual) {
2953 AudioProcessing::Config::GainController1 a;
2954 AudioProcessing::Config::GainController1 b;
2955 EXPECT_EQ(a, b);
2956
2957 Toggle(a.enabled);
2958 b.enabled = a.enabled;
2959 EXPECT_EQ(a, b);
2960
2961 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2962 b.mode = a.mode;
2963 EXPECT_EQ(a, b);
2964
2965 a.target_level_dbfs++;
2966 b.target_level_dbfs = a.target_level_dbfs;
2967 EXPECT_EQ(a, b);
2968
2969 a.compression_gain_db++;
2970 b.compression_gain_db = a.compression_gain_db;
2971 EXPECT_EQ(a, b);
2972
2973 Toggle(a.enable_limiter);
2974 b.enable_limiter = a.enable_limiter;
2975 EXPECT_EQ(a, b);
2976
Alessio Bazzica3438a932020-10-14 12:47:50 +02002977 auto& a_analog = a.analog_gain_controller;
2978 auto& b_analog = b.analog_gain_controller;
2979
2980 Toggle(a_analog.enabled);
2981 b_analog.enabled = a_analog.enabled;
2982 EXPECT_EQ(a, b);
2983
2984 a_analog.startup_min_volume++;
2985 b_analog.startup_min_volume = a_analog.startup_min_volume;
2986 EXPECT_EQ(a, b);
2987
2988 a_analog.clipped_level_min++;
2989 b_analog.clipped_level_min = a_analog.clipped_level_min;
2990 EXPECT_EQ(a, b);
2991
Alessio Bazzica3438a932020-10-14 12:47:50 +02002992 Toggle(a_analog.enable_digital_adaptive);
2993 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2994 EXPECT_EQ(a, b);
2995}
2996
2997// Checks that one differing parameter is sufficient to make two configs
2998// different.
2999TEST(AudioProcessing, GainController1ConfigNotEqual) {
3000 AudioProcessing::Config::GainController1 a;
3001 const AudioProcessing::Config::GainController1 b;
3002
3003 Toggle(a.enabled);
3004 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003005 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003006
3007 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
3008 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003009 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003010
3011 a.target_level_dbfs++;
3012 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003013 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003014
3015 a.compression_gain_db++;
3016 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003017 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003018
3019 Toggle(a.enable_limiter);
3020 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003021 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003022
Alessio Bazzica3438a932020-10-14 12:47:50 +02003023 auto& a_analog = a.analog_gain_controller;
3024 const auto& b_analog = b.analog_gain_controller;
3025
3026 Toggle(a_analog.enabled);
3027 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003028 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003029
3030 a_analog.startup_min_volume++;
3031 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003032 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003033
3034 a_analog.clipped_level_min++;
3035 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003036 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003037
Alessio Bazzica3438a932020-10-14 12:47:50 +02003038 Toggle(a_analog.enable_digital_adaptive);
3039 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003040 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003041}
3042
3043TEST(AudioProcessing, GainController2ConfigEqual) {
3044 AudioProcessing::Config::GainController2 a;
3045 AudioProcessing::Config::GainController2 b;
3046 EXPECT_EQ(a, b);
3047
3048 Toggle(a.enabled);
3049 b.enabled = a.enabled;
3050 EXPECT_EQ(a, b);
3051
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003052 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003053 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3054 EXPECT_EQ(a, b);
3055
3056 auto& a_adaptive = a.adaptive_digital;
3057 auto& b_adaptive = b.adaptive_digital;
3058
3059 Toggle(a_adaptive.enabled);
3060 b_adaptive.enabled = a_adaptive.enabled;
3061 EXPECT_EQ(a, b);
3062
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003063 Toggle(a_adaptive.dry_run);
3064 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003065 EXPECT_EQ(a, b);
3066
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003067 a_adaptive.headroom_db += 1.0f;
3068 b_adaptive.headroom_db = a_adaptive.headroom_db;
3069 EXPECT_EQ(a, b);
3070
3071 a_adaptive.max_gain_db += 1.0f;
3072 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3073 EXPECT_EQ(a, b);
3074
3075 a_adaptive.initial_gain_db += 1.0f;
3076 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3077 EXPECT_EQ(a, b);
3078
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003079 a_adaptive.vad_reset_period_ms++;
3080 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003081 EXPECT_EQ(a, b);
3082
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003083 a_adaptive.adjacent_speech_frames_threshold++;
3084 b_adaptive.adjacent_speech_frames_threshold =
3085 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003086 EXPECT_EQ(a, b);
3087
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003088 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003089 b_adaptive.max_gain_change_db_per_second =
3090 a_adaptive.max_gain_change_db_per_second;
3091 EXPECT_EQ(a, b);
3092
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003093 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003094 b_adaptive.max_output_noise_level_dbfs =
3095 a_adaptive.max_output_noise_level_dbfs;
3096 EXPECT_EQ(a, b);
3097}
3098
3099// Checks that one differing parameter is sufficient to make two configs
3100// different.
3101TEST(AudioProcessing, GainController2ConfigNotEqual) {
3102 AudioProcessing::Config::GainController2 a;
3103 const AudioProcessing::Config::GainController2 b;
3104
3105 Toggle(a.enabled);
3106 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003107 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003108
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003109 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003110 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003111 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003112
3113 auto& a_adaptive = a.adaptive_digital;
3114 const auto& b_adaptive = b.adaptive_digital;
3115
3116 Toggle(a_adaptive.enabled);
3117 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003118 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003119
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003120 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003121 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003122 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003123
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003124 a_adaptive.headroom_db += 1.0f;
3125 EXPECT_NE(a, b);
3126 a_adaptive = b_adaptive;
3127
3128 a_adaptive.max_gain_db += 1.0f;
3129 EXPECT_NE(a, b);
3130 a_adaptive = b_adaptive;
3131
3132 a_adaptive.initial_gain_db += 1.0f;
3133 EXPECT_NE(a, b);
3134 a_adaptive = b_adaptive;
3135
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003136 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003137 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003138 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003139
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003140 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003141 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003142 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003143
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003144 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003145 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003146 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003147
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003148 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003149 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003150 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003151}
3152
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003153} // namespace webrtc