blob: 32cf9a866c7699b6a3ab900996dc6105dfe39ebc [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()
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000053#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000054#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000055#else
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020056#include "modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000057#endif
kwiberg77eab702016-09-28 17:42:01 -070058RTC_POP_IGNORING_WUNDEF()
niklase@google.com470e71d2011-07-07 08:21:25 +000059
Sam Zackrisson6558fa52019-08-26 10:12:41 +020060ABSL_FLAG(bool,
61 write_apm_ref_data,
62 false,
63 "Write ApmTest.Process results to file, instead of comparing results "
64 "to the existing reference data file.");
65
andrew@webrtc.org27c69802014-02-18 20:24:56 +000066namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000067namespace {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000068
Sam Zackrisson3bd444f2022-08-03 14:37:00 +020069// All sample rates used by APM internally during processing. Other input /
70// output rates are resampled to / from one of these.
71const int kProcessSampleRates[] = {16000, 32000, 48000};
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000072
ekmeyerson60d9b332015-08-14 10:35:55 -070073enum StreamDirection { kForward = 0, kReverse };
74
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000075void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 19:08:33 +020076 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
77 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000078 cb_int.channels());
Peter Kasting69558702016-01-12 16:26:35 -080079 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +020080 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000081 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000082}
andrew@webrtc.org17e40642014-03-04 20:58:13 +000083
Per Åhgren2507f8c2020-03-19 12:33:29 +010084void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
85 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000086}
87
Jonas Olssona4d87372019-07-05 19:08:33 +020088void MixStereoToMono(const float* stereo,
89 float* mono,
pkasting25702cb2016-01-08 13:50:27 -080090 size_t samples_per_channel) {
91 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000092 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +000093}
94
Jonas Olssona4d87372019-07-05 19:08:33 +020095void MixStereoToMono(const int16_t* stereo,
96 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -080097 size_t samples_per_channel) {
98 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000099 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
100}
101
pkasting25702cb2016-01-08 13:50:27 -0800102void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
103 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000104 stereo[i * 2 + 1] = stereo[i * 2];
105 }
106}
107
yujo36b1a5f2017-06-12 12:45:32 -0700108void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800109 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000110 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
111 }
112}
113
Per Åhgren2507f8c2020-03-19 12:33:29 +0100114void SetFrameTo(Int16FrameData* frame, int16_t value) {
115 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700116 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100117 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000118 }
119}
120
Per Åhgren2507f8c2020-03-19 12:33:29 +0100121void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
122 ASSERT_EQ(2u, frame->num_channels);
123 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
124 frame->data[i] = left;
125 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000126 }
127}
128
Per Åhgren2507f8c2020-03-19 12:33:29 +0100129void ScaleFrame(Int16FrameData* frame, float scale) {
130 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700131 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100132 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000133 }
134}
135
Per Åhgren2507f8c2020-03-19 12:33:29 +0100136bool FrameDataAreEqual(const Int16FrameData& frame1,
137 const Int16FrameData& frame2) {
138 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000139 return false;
140 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100141 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000142 return false;
143 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100144 if (memcmp(
145 frame1.data.data(), frame2.data.data(),
146 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000147 return false;
148 }
149 return true;
150}
151
Per Åhgren2507f8c2020-03-19 12:33:29 +0100152rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
153 int16_t* ptr = frame->data.data();
154 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200155 return rtc::ArrayView<int16_t>(ptr, len);
156}
157
Per Åhgren2507f8c2020-03-19 12:33:29 +0100158rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
159 const int16_t* ptr = frame.data.data();
160 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200161 return rtc::ArrayView<const int16_t>(ptr, len);
162}
163
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000164void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200165 AudioProcessing::Config apm_config = ap->GetConfig();
166 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000167#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200168 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100169
170 apm_config.gain_controller1.enabled = true;
171 apm_config.gain_controller1.mode =
172 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000173#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200174 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000175
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100176 apm_config.gain_controller1.enabled = true;
177 apm_config.gain_controller1.mode =
178 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000179#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000180
saza0bad15f2019-10-16 11:46:11 +0200181 apm_config.noise_suppression.enabled = true;
182
peah8271d042016-11-22 07:24:52 -0800183 apm_config.high_pass_filter.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100184 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800185 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000186}
187
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000188// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000189template <class T>
190T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200191 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000192}
193
Per Åhgren2507f8c2020-03-19 12:33:29 +0100194int16_t MaxAudioFrame(const Int16FrameData& frame) {
195 const size_t length = frame.samples_per_channel * frame.num_channels;
196 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800197 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100198 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000199 }
200
201 return max_data;
202}
203
Alex Loiko890988c2017-08-31 10:25:48 +0200204void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700205 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000206 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000207 ASSERT_TRUE(file != NULL);
208
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100209 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000210 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800211 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000212 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000213
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000214 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000215 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200216 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000217 fclose(file);
218}
219
Alex Loiko890988c2017-08-31 10:25:48 +0200220std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200221 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000222 // Resource files are all stereo.
223 ss << name << sample_rate_hz / 1000 << "_stereo";
224 return test::ResourcePath(ss.str(), "pcm");
225}
226
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000227// Temporary filenames unique to this process. Used to be able to run these
228// tests in parallel as each process needs to be running in isolation they can't
229// have competing filenames.
230std::map<std::string, std::string> temp_filenames;
231
Alex Loiko890988c2017-08-31 10:25:48 +0200232std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000233 int input_rate,
234 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700235 int reverse_input_rate,
236 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800237 size_t num_input_channels,
238 size_t num_output_channels,
239 size_t num_reverse_input_channels,
240 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700241 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200242 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700243 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
244 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000245 if (num_output_channels == 1) {
246 ss << "mono";
247 } else if (num_output_channels == 2) {
248 ss << "stereo";
249 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100250 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000251 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700252 ss << output_rate / 1000;
253 if (num_reverse_output_channels == 1) {
254 ss << "_rmono";
255 } else if (num_reverse_output_channels == 2) {
256 ss << "_rstereo";
257 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100258 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700259 }
260 ss << reverse_output_rate / 1000;
261 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000262
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000263 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700264 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000265 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
266 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000267}
268
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000269void ClearTempFiles() {
270 for (auto& kv : temp_filenames)
271 remove(kv.second.c_str());
272}
273
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200274// Only remove "out" files. Keep "ref" files.
275void ClearTempOutFiles() {
276 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
277 const std::string& filename = it->first;
278 if (filename.substr(0, 3).compare("out") == 0) {
279 remove(it->second.c_str());
280 temp_filenames.erase(it++);
281 } else {
282 it++;
283 }
284 }
285}
286
Alex Loiko890988c2017-08-31 10:25:48 +0200287void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000288 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000289 ASSERT_TRUE(file != NULL);
290 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000291 fclose(file);
292}
293
Sam Zackrisson3bd444f2022-08-03 14:37:00 +0200294// Reads a 10 ms chunk (actually AudioProcessing::GetFrameSize() samples per
295// channel) of int16 interleaved audio from the given (assumed stereo) file,
296// converts to deinterleaved float (optionally downmixing) and returns the
297// result in `cb`. Returns false if the file ended (or on error) and true
298// otherwise.
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000299//
Artem Titov0b489302021-07-28 20:50:03 +0200300// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000301// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200302bool ReadChunk(FILE* file,
303 int16_t* int_data,
304 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000305 ChannelBuffer<float>* cb) {
306 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000307 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000308 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
309 if (read_count != frame_size) {
310 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700311 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000312 return false; // This is expected.
313 }
314
315 S16ToFloat(int_data, frame_size, float_data);
316 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000317 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000318 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200319 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000320 }
321
322 return true;
323}
324
Per Åhgrena43178c2020-09-25 12:02:32 +0200325// Returns the reference file name that matches the current CPU
326// architecture/optimizations.
327std::string GetReferenceFilename() {
328#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
329 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
330#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
331 if (GetCPUInfo(kAVX2) != 0) {
332 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
333 }
334 return test::ResourcePath("audio_processing/output_data_float", "pb");
335#endif
336}
337
niklase@google.com470e71d2011-07-07 08:21:25 +0000338class ApmTest : public ::testing::Test {
339 protected:
340 ApmTest();
341 virtual void SetUp();
342 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000343
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200344 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000345
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200346 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000347
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000348 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200349 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000350
351 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000352 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000353 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800354 size_t num_input_channels,
355 size_t num_output_channels,
356 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000357 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000358 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000359 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100360 bool ReadFrame(FILE* file, Int16FrameData* frame);
361 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
362 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200363 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100364 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000365 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200366 void ProcessDelayVerificationTest(int delay_ms,
367 int system_delay_ms,
368 int delay_min,
369 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700370 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800371 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700372 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800373 void TestChangingForwardChannels(size_t num_in_channels,
374 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700375 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800376 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700377 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000378 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
379 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000380 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000381 int ProcessStreamChooser(Format format);
382 int AnalyzeReverseStreamChooser(Format format);
383 void ProcessDebugDump(const std::string& in_filename,
384 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800385 Format format,
386 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000387 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000388
389 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000390 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200391 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100392 Int16FrameData frame_;
393 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 15:40:04 +0100394 std::unique_ptr<ChannelBuffer<float>> float_cb_;
395 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000396 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800397 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000398 FILE* far_file_;
399 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000400 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000401};
402
403ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000404 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200405 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000406 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000407 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000408 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000409 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000410 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200411 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100412 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100413 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100414 apm_config.pipeline.maximum_internal_processing_rate = 48000;
415 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000416}
niklase@google.com470e71d2011-07-07 08:21:25 +0000417
418void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000419 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000420
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000421 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000422}
423
424void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 if (far_file_) {
426 ASSERT_EQ(0, fclose(far_file_));
427 }
428 far_file_ = NULL;
429
430 if (near_file_) {
431 ASSERT_EQ(0, fclose(near_file_));
432 }
433 near_file_ = NULL;
434
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000435 if (out_file_) {
436 ASSERT_EQ(0, fclose(out_file_));
437 }
438 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000439}
440
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000441void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200442 ASSERT_EQ(
443 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100444 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200445 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100446 {revframe_.sample_rate_hz, revframe_.num_channels},
447 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000448}
449
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000450void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000451 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000452 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800453 size_t num_input_channels,
454 size_t num_output_channels,
455 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000456 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200457 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000458 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000459 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000460
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200461 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000462 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000463 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000464
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000465 if (far_file_) {
466 ASSERT_EQ(0, fclose(far_file_));
467 }
468 std::string filename = ResourceFilePath("far", sample_rate_hz);
469 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200470 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000471
472 if (near_file_) {
473 ASSERT_EQ(0, fclose(near_file_));
474 }
475 filename = ResourceFilePath("near", sample_rate_hz);
476 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200477 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000478
479 if (open_output_file) {
480 if (out_file_) {
481 ASSERT_EQ(0, fclose(out_file_));
482 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700483 filename = OutputFilePath(
484 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
485 reverse_sample_rate_hz, num_input_channels, num_output_channels,
486 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000487 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200488 ASSERT_TRUE(out_file_ != NULL)
489 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000490 }
491}
492
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000493void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000494 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000495}
496
Jonas Olssona4d87372019-07-05 19:08:33 +0200497bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100498 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000499 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000500 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100501 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200502 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100503 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000504 if (read_count != frame_size) {
505 // Check that the file really ended.
506 EXPECT_NE(0, feof(file));
507 return false; // This is expected.
508 }
509
Per Åhgren2507f8c2020-03-19 12:33:29 +0100510 if (frame->num_channels == 1) {
511 MixStereoToMono(frame->data.data(), frame->data.data(),
512 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000513 }
514
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000515 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000516 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000517 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000518 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000519}
520
Per Åhgren2507f8c2020-03-19 12:33:29 +0100521bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000522 return ReadFrame(file, frame, NULL);
523}
524
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000525// If the end of the file has been reached, rewind it and attempt to read the
526// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200527void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100528 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000529 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200530 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000531 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200532 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000533 }
534}
535
Per Åhgren2507f8c2020-03-19 12:33:29 +0100536void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000537 ReadFrameWithRewind(file, frame, NULL);
538}
539
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000540int ApmTest::ProcessStreamChooser(Format format) {
541 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100542 return apm_->ProcessStream(
543 frame_.data.data(),
544 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
545 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100546 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000547 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200548 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100549 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100550 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100551 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200552 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000553}
554
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000555int ApmTest::AnalyzeReverseStreamChooser(Format format) {
556 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100557 return apm_->ProcessReverseStream(
558 revframe_.data.data(),
559 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
560 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
561 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000562 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000563 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100564 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100565 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000566}
567
Jonas Olssona4d87372019-07-05 19:08:33 +0200568void ApmTest::ProcessDelayVerificationTest(int delay_ms,
569 int system_delay_ms,
570 int delay_min,
571 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200572 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000573 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100574 Int16FrameData tmp_frame;
575 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000576 bool causal = true;
577
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200578 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000579 SetFrameTo(&tmp_frame, 0);
580
581 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200582 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000583 int frame_delay = delay_ms / 10;
584 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100585 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000586 frame->CopyFrom(tmp_frame);
587 frame_queue.push(frame);
588 frame_delay++;
589 causal = false;
590 }
591 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100592 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000593 frame->CopyFrom(tmp_frame);
594 frame_queue.push(frame);
595 frame_delay--;
596 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000597 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
598 // need enough frames with audio to have reliable estimates, but as few as
599 // possible to keep processing time down. 4.5 seconds seemed to be a good
600 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000601 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100602 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000603 frame->CopyFrom(tmp_frame);
604 // Use the near end recording, since that has more speech in it.
605 ASSERT_TRUE(ReadFrame(near_file_, frame));
606 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100607 Int16FrameData* reverse_frame = frame;
608 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000609 if (!causal) {
610 reverse_frame = frame_queue.front();
611 // When we call ProcessStream() the frame is modified, so we can't use the
612 // pointer directly when things are non-causal. Use an intermediate frame
613 // and copy the data.
614 process_frame = &tmp_frame;
615 process_frame->CopyFrom(*frame);
616 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100617 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
618 reverse_frame->data.data(),
619 StreamConfig(reverse_frame->sample_rate_hz,
620 reverse_frame->num_channels),
621 StreamConfig(reverse_frame->sample_rate_hz,
622 reverse_frame->num_channels),
623 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000624 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100625 EXPECT_EQ(apm_->kNoError,
626 apm_->ProcessStream(process_frame->data.data(),
627 StreamConfig(process_frame->sample_rate_hz,
628 process_frame->num_channels),
629 StreamConfig(process_frame->sample_rate_hz,
630 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100631 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000632 frame = frame_queue.front();
633 frame_queue.pop();
634 delete frame;
635
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000636 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000637 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100638 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000639 }
640 }
641
642 rewind(near_file_);
643 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100644 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000645 frame_queue.pop();
646 delete frame;
647 }
648 // Calculate expected delay estimate and acceptable regions. Further,
649 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700650 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100651 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700652 const int expected_median =
653 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
654 const int expected_median_high = rtc::SafeClamp<int>(
655 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700656 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700657 const int expected_median_low = rtc::SafeClamp<int>(
658 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700659 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000660 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100661 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200662 ASSERT_TRUE(stats.delay_median_ms.has_value());
663 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000664 EXPECT_GE(expected_median_high, median);
665 EXPECT_LE(expected_median_low, median);
666}
667
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000668void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000670 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000671
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000672 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200673 AudioProcessing::Config apm_config = apm_->GetConfig();
674 apm_config.gain_controller1.enabled = true;
675 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200676 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000677
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000678 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200679 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000680 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200681 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000682
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000683 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200684 apm_config.echo_canceller.enabled = true;
685 apm_config.echo_canceller.mobile_mode = false;
686 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000687 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200688 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200689 apm_config.gain_controller1.enabled = false;
690 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000691
692 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000693 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100694 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000695
696 // Resets after successful ProcessStream().
697 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000698 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100699 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000700
701 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200702 apm_config.gain_controller1.enabled = true;
703 apm_->ApplyConfig(apm_config);
704 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100705 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200706 apm_config.gain_controller1.enabled = false;
707 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000708
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000709 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200710 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100711 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000712
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000713 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000714 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200715 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000716 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000717}
718
719TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000720 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000721}
722
723TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000724 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000725}
726
Michael Graczyk86c6d332015-07-23 11:41:39 -0700727void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800728 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700729 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100730 frame_.num_channels = num_channels;
731
732 EXPECT_EQ(expected_return,
733 apm_->ProcessStream(
734 frame_.data.data(),
735 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
736 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100737 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100738 EXPECT_EQ(expected_return,
739 apm_->ProcessReverseStream(
740 frame_.data.data(),
741 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
742 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
743 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000744}
745
Michael Graczyk86c6d332015-07-23 11:41:39 -0700746void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800747 size_t num_in_channels,
748 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700749 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100750 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700751 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
752
753 EXPECT_EQ(expected_return,
754 apm_->ProcessStream(float_cb_->channels(), input_stream,
755 output_stream, float_cb_->channels()));
756}
757
758void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800759 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700760 AudioProcessing::Error expected_return) {
761 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100762 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700763 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100764 {frame_.sample_rate_hz, num_rev_channels},
765 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700766
ekmeyerson60d9b332015-08-14 10:35:55 -0700767 EXPECT_EQ(
768 expected_return,
769 apm_->ProcessReverseStream(
770 float_cb_->channels(), processing_config.reverse_input_stream(),
771 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700772}
773
774TEST_F(ApmTest, ChannelsInt16Interface) {
775 // Testing number of invalid and valid channels.
776 Init(16000, 16000, 16000, 4, 4, 4, false);
777
778 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
779
Peter Kasting69558702016-01-12 16:26:35 -0800780 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700781 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000782 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000783 }
784}
785
Michael Graczyk86c6d332015-07-23 11:41:39 -0700786TEST_F(ApmTest, Channels) {
787 // Testing number of invalid and valid channels.
788 Init(16000, 16000, 16000, 4, 4, 4, false);
789
790 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
791 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
792
Peter Kasting69558702016-01-12 16:26:35 -0800793 for (size_t i = 1; i < 4; ++i) {
794 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700795 // Output channels much be one or match input channels.
796 if (j == 1 || i == j) {
797 TestChangingForwardChannels(i, j, kNoErr);
798 TestChangingReverseChannels(i, kNoErr);
799
800 EXPECT_EQ(i, apm_->num_input_channels());
801 EXPECT_EQ(j, apm_->num_output_channels());
802 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800803 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700804 } else {
805 TestChangingForwardChannels(i, j,
806 AudioProcessing::kBadNumberChannelsError);
807 }
808 }
809 }
810}
811
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000812TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100813 // Testing some valid sample rates.
814 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
815 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000816 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000817 }
818}
819
Sam Zackrissone277bde2019-10-25 10:07:54 +0200820// This test repeatedly reconfigures the pre-amplifier in APM, processes a
821// number of frames, and checks that output signal has the right level.
822TEST_F(ApmTest, PreAmplifier) {
823 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200824 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100825 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200826 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100827 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200828 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
829 }
830 }
831 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100832 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200833 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200834
Per Åhgren2507f8c2020-03-19 12:33:29 +0100835 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200836 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
837 return std::accumulate(data.begin(), data.end(), 0.0f,
838 [](float a, float b) { return a + b * b; }) /
839 data.size() / 32768 / 32768;
840 };
841
842 const float input_power = compute_power(tmp_frame);
843 // Double-check that the input data is large compared to the error kEpsilon.
844 constexpr float kEpsilon = 1e-4f;
845 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
846
847 // 1. Enable pre-amp with 0 dB gain.
848 AudioProcessing::Config config = apm_->GetConfig();
849 config.pre_amplifier.enabled = true;
850 config.pre_amplifier.fixed_gain_factor = 1.0f;
851 apm_->ApplyConfig(config);
852
853 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200854 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200855 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
856 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200857 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200858 EXPECT_NEAR(output_power, input_power, kEpsilon);
859 config = apm_->GetConfig();
860 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
861
862 // 2. Change pre-amp gain via ApplyConfig.
863 config.pre_amplifier.fixed_gain_factor = 2.0f;
864 apm_->ApplyConfig(config);
865
866 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200867 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200868 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
869 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200870 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200871 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
872 config = apm_->GetConfig();
873 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
874
875 // 3. Change pre-amp gain via a RuntimeSetting.
876 apm_->SetRuntimeSetting(
877 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
878
879 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200880 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200881 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
882 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200883 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200884 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
885 config = apm_->GetConfig();
886 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
887}
888
Per Åhgrendb5d7282021-03-15 16:31:04 +0000889// This test a simple test that ensures that the emulated analog mic gain
890// functionality runs without crashing.
891TEST_F(ApmTest, AnalogMicGainEmulation) {
892 // Fill the audio frame with a sawtooth pattern.
893 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
894 const size_t samples_per_channel = frame_.samples_per_channel;
895 for (size_t i = 0; i < samples_per_channel; i++) {
896 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
897 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
898 }
899 }
900 // Cache the frame in tmp_frame.
901 Int16FrameData tmp_frame;
902 tmp_frame.CopyFrom(frame_);
903
904 // Enable the analog gain emulation.
905 AudioProcessing::Config config = apm_->GetConfig();
906 config.capture_level_adjustment.enabled = true;
907 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
908 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
909 config.gain_controller1.enabled = true;
910 config.gain_controller1.mode =
911 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
912 config.gain_controller1.analog_gain_controller.enabled = true;
913 apm_->ApplyConfig(config);
914
915 // Process a number of frames to ensure that the code runs without crashes.
916 for (int i = 0; i < 20; ++i) {
917 frame_.CopyFrom(tmp_frame);
918 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
919 }
920}
921
922// This test repeatedly reconfigures the capture level adjustment functionality
923// in APM, processes a number of frames, and checks that output signal has the
924// right level.
925TEST_F(ApmTest, CaptureLevelAdjustment) {
926 // Fill the audio frame with a sawtooth pattern.
927 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
928 const size_t samples_per_channel = frame_.samples_per_channel;
929 for (size_t i = 0; i < samples_per_channel; i++) {
930 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
931 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
932 }
933 }
934 // Cache the frame in tmp_frame.
935 Int16FrameData tmp_frame;
936 tmp_frame.CopyFrom(frame_);
937
938 auto compute_power = [](const Int16FrameData& frame) {
939 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
940 return std::accumulate(data.begin(), data.end(), 0.0f,
941 [](float a, float b) { return a + b * b; }) /
942 data.size() / 32768 / 32768;
943 };
944
945 const float input_power = compute_power(tmp_frame);
946 // Double-check that the input data is large compared to the error kEpsilon.
947 constexpr float kEpsilon = 1e-20f;
948 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
949
950 // 1. Enable pre-amp with 0 dB gain.
951 AudioProcessing::Config config = apm_->GetConfig();
952 config.capture_level_adjustment.enabled = true;
953 config.capture_level_adjustment.pre_gain_factor = 0.5f;
954 config.capture_level_adjustment.post_gain_factor = 4.f;
955 const float expected_output_power1 =
956 config.capture_level_adjustment.pre_gain_factor *
957 config.capture_level_adjustment.pre_gain_factor *
958 config.capture_level_adjustment.post_gain_factor *
959 config.capture_level_adjustment.post_gain_factor * input_power;
960 apm_->ApplyConfig(config);
961
962 for (int i = 0; i < 20; ++i) {
963 frame_.CopyFrom(tmp_frame);
964 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
965 }
966 float output_power = compute_power(frame_);
967 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
968 config = apm_->GetConfig();
969 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
970 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
971
972 // 2. Change pre-amp gain via ApplyConfig.
973 config.capture_level_adjustment.pre_gain_factor = 1.0f;
974 config.capture_level_adjustment.post_gain_factor = 2.f;
975 const float expected_output_power2 =
976 config.capture_level_adjustment.pre_gain_factor *
977 config.capture_level_adjustment.pre_gain_factor *
978 config.capture_level_adjustment.post_gain_factor *
979 config.capture_level_adjustment.post_gain_factor * input_power;
980 apm_->ApplyConfig(config);
981
982 for (int i = 0; i < 20; ++i) {
983 frame_.CopyFrom(tmp_frame);
984 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
985 }
986 output_power = compute_power(frame_);
987 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
988 config = apm_->GetConfig();
989 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
990 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
991
992 // 3. Change pre-amp gain via a RuntimeSetting.
993 constexpr float kPreGain3 = 0.5f;
994 constexpr float kPostGain3 = 3.f;
995 const float expected_output_power3 =
996 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
997
998 apm_->SetRuntimeSetting(
999 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1000 apm_->SetRuntimeSetting(
1001 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1002
1003 for (int i = 0; i < 20; ++i) {
1004 frame_.CopyFrom(tmp_frame);
1005 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1006 }
1007 output_power = compute_power(frame_);
1008 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1009 config = apm_->GetConfig();
1010 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1011 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1012}
1013
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001014TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001015 AudioProcessing::Config config = apm_->GetConfig();
1016 config.gain_controller1.enabled = false;
1017 apm_->ApplyConfig(config);
1018 config.gain_controller1.enabled = true;
1019 apm_->ApplyConfig(config);
1020
niklase@google.com470e71d2011-07-07 08:21:25 +00001021 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001022 for (auto mode :
1023 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1024 AudioProcessing::Config::GainController1::kFixedDigital,
1025 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1026 config.gain_controller1.mode = mode;
1027 apm_->ApplyConfig(config);
1028 apm_->set_stream_analog_level(100);
1029 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001031
Sam Zackrisson41478c72019-10-15 10:10:26 +02001032 // Testing target levels
1033 for (int target_level_dbfs : {0, 15, 31}) {
1034 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1035 apm_->ApplyConfig(config);
1036 apm_->set_stream_analog_level(100);
1037 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 }
1039
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001040 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001041 for (int compression_gain_db : {0, 10, 90}) {
1042 config.gain_controller1.compression_gain_db = compression_gain_db;
1043 apm_->ApplyConfig(config);
1044 apm_->set_stream_analog_level(100);
1045 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 }
1047
1048 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001049 for (bool enable : {false, true}) {
1050 config.gain_controller1.enable_limiter = enable;
1051 apm_->ApplyConfig(config);
1052 apm_->set_stream_analog_level(100);
1053 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1054 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001055
Hanna Silencd597042021-11-02 11:02:48 +01001056 // Testing level limits.
1057 constexpr int kMinLevel = 0;
1058 constexpr int kMaxLevel = 255;
1059 apm_->set_stream_analog_level(kMinLevel);
1060 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1061 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1062 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1063 apm_->set_stream_analog_level(kMaxLevel);
1064 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001065}
1066
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001067#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001068using ApmDeathTest = ApmTest;
1069
1070TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001071 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001072 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001073 config.gain_controller1.target_level_dbfs = -1;
1074 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001075}
1076
Tommia5e07cc2020-05-26 21:40:37 +02001077TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001078 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001079 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001080 config.gain_controller1.target_level_dbfs = 32;
1081 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001082}
1083
Tommia5e07cc2020-05-26 21:40:37 +02001084TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001085 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001086 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001087 config.gain_controller1.compression_gain_db = -1;
1088 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001089}
1090
Tommia5e07cc2020-05-26 21:40:37 +02001091TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001092 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001093 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001094 config.gain_controller1.compression_gain_db = 91;
1095 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001096}
1097
Tommia5e07cc2020-05-26 21:40:37 +02001098TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001099 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001100 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001101 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001102 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001103}
1104
Tommia5e07cc2020-05-26 21:40:37 +02001105TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001106 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001107 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001108 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001109 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001110}
1111#endif
1112
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001113void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001114 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001115 auto config = apm_->GetConfig();
1116 config.gain_controller1.enabled = true;
1117 config.gain_controller1.mode =
1118 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1119 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001120
1121 int out_analog_level = 0;
1122 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001123 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001124 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001125 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001126
1127 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001128 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001129 EXPECT_EQ(apm_->kNoError,
1130 apm_->ProcessStream(
1131 frame_.data.data(),
1132 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1133 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001134 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001135 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001136 }
1137
1138 // Ensure the AGC is still able to reach the maximum.
1139 EXPECT_EQ(255, out_analog_level);
1140}
1141
1142// Verifies that despite volume slider quantization, the AGC can continue to
1143// increase its volume.
1144TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001145 for (size_t sample_rate_hz : kProcessSampleRates) {
1146 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1147 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001148 }
1149}
1150
1151void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001152 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001153 auto config = apm_->GetConfig();
1154 config.gain_controller1.enabled = true;
1155 config.gain_controller1.mode =
1156 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1157 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001158
1159 int out_analog_level = 100;
1160 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001161 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001162 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001163 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001164
Sam Zackrisson41478c72019-10-15 10:10:26 +02001165 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001166 EXPECT_EQ(apm_->kNoError,
1167 apm_->ProcessStream(
1168 frame_.data.data(),
1169 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1170 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001171 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001172 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001173 }
1174
1175 // Ensure the volume was raised.
1176 EXPECT_GT(out_analog_level, 100);
1177 int highest_level_reached = out_analog_level;
1178 // Simulate a user manual volume change.
1179 out_analog_level = 100;
1180
1181 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001182 ReadFrameWithRewind(near_file_, &frame_);
1183 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001184
Sam Zackrisson41478c72019-10-15 10:10:26 +02001185 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001186 EXPECT_EQ(apm_->kNoError,
1187 apm_->ProcessStream(
1188 frame_.data.data(),
1189 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1190 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001191 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001192 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001193 // Check that AGC respected the manually adjusted volume.
1194 EXPECT_LT(out_analog_level, highest_level_reached);
1195 }
1196 // Check that the volume was still raised.
1197 EXPECT_GT(out_analog_level, 100);
1198}
1199
1200TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001201 for (size_t sample_rate_hz : kProcessSampleRates) {
1202 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1203 RunManualVolumeChangeIsPossibleTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001204 }
1205}
1206
niklase@google.com470e71d2011-07-07 08:21:25 +00001207TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001208 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001209 AudioProcessing::Config apm_config;
1210 apm_config.high_pass_filter.enabled = true;
1211 apm_->ApplyConfig(apm_config);
1212 apm_config.high_pass_filter.enabled = false;
1213 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001214}
1215
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001216TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001217 AudioProcessing::Config config = apm_->GetConfig();
1218 EXPECT_FALSE(config.echo_canceller.enabled);
1219 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001220 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001221 EXPECT_FALSE(config.noise_suppression.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001222}
1223
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001224TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledInt) {
1225 // Test that ProcessStream simply copies input to output when all components
1226 // are disabled.
1227 // Runs over all processing rates, and some particularly common or special
1228 // rates.
1229 // - 8000 Hz: lowest sample rate seen in Chrome metrics,
1230 // - 22050 Hz: APM input/output frames are not exactly 10 ms,
1231 // - 44100 Hz: very common desktop sample rate.
1232 constexpr int kSampleRatesHz[] = {8000, 16000, 22050, 32000, 44100, 48000};
1233 for (size_t sample_rate_hz : kSampleRatesHz) {
1234 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1235 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001236 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001237 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001238 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001239 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001240 EXPECT_EQ(apm_->kNoError,
1241 apm_->ProcessStream(
1242 frame_.data.data(),
1243 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1244 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001245 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001246 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001247 EXPECT_EQ(apm_->kNoError,
1248 apm_->ProcessReverseStream(
1249 frame_.data.data(),
1250 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1251 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1252 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001253 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001254 }
1255 }
1256}
1257
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001258TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001259 // Test that ProcessStream simply copies input to output when all components
1260 // are disabled.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001261 const size_t kSamples = 160;
1262 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001263 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001264 float dest[kSamples] = {};
1265
1266 auto src_channels = &src[0];
1267 auto dest_channels = &dest[0];
1268
Niels Möller4f776ac2021-07-02 11:30:54 +02001269 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001270 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1271 StreamConfig(sample_rate, 1),
1272 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001273
1274 for (size_t i = 0; i < kSamples; ++i) {
1275 EXPECT_EQ(src[i], dest[i]);
1276 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001277
1278 // Same for ProcessReverseStream.
1279 float rev_dest[kSamples] = {};
1280 auto rev_dest_channels = &rev_dest[0];
1281
1282 StreamConfig input_stream = {sample_rate, 1};
1283 StreamConfig output_stream = {sample_rate, 1};
1284 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1285 output_stream, &rev_dest_channels));
1286
1287 for (size_t i = 0; i < kSamples; ++i) {
1288 EXPECT_EQ(src[i], rev_dest[i]);
1289 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001290}
1291
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001292TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1293 EnableAllComponents();
1294
pkasting25702cb2016-01-08 13:50:27 -08001295 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001296 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1297 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001298 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001299 ASSERT_EQ(0, feof(far_file_));
1300 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001301 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001302 CopyLeftToRightChannel(revframe_.data.data(),
1303 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001304
Per Åhgren2507f8c2020-03-19 12:33:29 +01001305 ASSERT_EQ(
1306 kNoErr,
1307 apm_->ProcessReverseStream(
1308 revframe_.data.data(),
1309 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1310 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1311 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001312
Per Åhgren2507f8c2020-03-19 12:33:29 +01001313 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001314
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001315 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001316 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001317 ASSERT_EQ(kNoErr,
1318 apm_->ProcessStream(
1319 frame_.data.data(),
1320 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1321 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001322 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001323 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001324
Per Åhgren2507f8c2020-03-19 12:33:29 +01001325 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001326 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001327 rewind(far_file_);
1328 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001329 }
1330}
1331
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001332TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001333 // Verify the filter is not active through undistorted audio when:
1334 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001335 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001336 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001337 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001338 EXPECT_EQ(apm_->kNoError,
1339 apm_->ProcessStream(
1340 frame_.data.data(),
1341 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1342 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001343 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001344 EXPECT_EQ(apm_->kNoError,
1345 apm_->ProcessStream(
1346 frame_.data.data(),
1347 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1348 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001349 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001350 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001351
1352 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001353 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001354 SetFrameTo(&frame_, 1000);
1355 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001356 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001357 EXPECT_EQ(apm_->kNoError,
1358 apm_->ProcessStream(
1359 frame_.data.data(),
1360 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1361 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001362 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001363 EXPECT_EQ(apm_->kNoError,
1364 apm_->ProcessStream(
1365 frame_.data.data(),
1366 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1367 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001368 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001369 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001370 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001371
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001372 // Check the test is valid. We should have distortion from the filter
1373 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001374 apm_config.echo_canceller.enabled = true;
1375 apm_config.echo_canceller.mobile_mode = false;
1376 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001377 frame_.samples_per_channel = 320;
1378 frame_.num_channels = 2;
1379 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001380 SetFrameTo(&frame_, 1000);
1381 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001382 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001383 EXPECT_EQ(apm_->kNoError,
1384 apm_->ProcessStream(
1385 frame_.data.data(),
1386 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1387 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001388 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001389 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001390}
1391
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001392#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1393void ApmTest::ProcessDebugDump(const std::string& in_filename,
1394 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001395 Format format,
1396 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001397 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001398 FILE* in_file = fopen(in_filename.c_str(), "rb");
1399 ASSERT_TRUE(in_file != NULL);
1400 audioproc::Event event_msg;
1401 bool first_init = true;
1402
1403 while (ReadMessageFromFile(in_file, &event_msg)) {
1404 if (event_msg.type() == audioproc::Event::INIT) {
1405 const audioproc::Init msg = event_msg.init();
1406 int reverse_sample_rate = msg.sample_rate();
1407 if (msg.has_reverse_sample_rate()) {
1408 reverse_sample_rate = msg.reverse_sample_rate();
1409 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001410 int output_sample_rate = msg.sample_rate();
1411 if (msg.has_output_sample_rate()) {
1412 output_sample_rate = msg.output_sample_rate();
1413 }
1414
Jonas Olssona4d87372019-07-05 19:08:33 +02001415 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1416 msg.num_input_channels(), msg.num_output_channels(),
1417 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001418 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001419 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001420 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001421 auto aec_dump =
1422 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1423 EXPECT_TRUE(aec_dump);
1424 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001425 first_init = false;
1426 }
1427
1428 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1429 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1430
1431 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001432 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001433 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001434 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001435 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1436 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001437 }
1438 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001439 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001440 if (format == kFloatFormat) {
1441 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001442 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001443 }
1444 }
1445 AnalyzeReverseStreamChooser(format);
1446
1447 } else if (event_msg.type() == audioproc::Event::STREAM) {
1448 const audioproc::Stream msg = event_msg.stream();
1449 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001450 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001451
Sam Zackrisson41478c72019-10-15 10:10:26 +02001452 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001453 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001454 if (msg.has_keypress()) {
1455 apm_->set_stream_key_pressed(msg.keypress());
1456 } else {
1457 apm_->set_stream_key_pressed(true);
1458 }
1459
1460 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001461 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001462 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001463 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001464 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1465 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001466 }
1467 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001468 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001469 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001470 if (format == kFloatFormat) {
1471 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001472 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001473 }
1474 }
1475 ProcessStreamChooser(format);
1476 }
1477 }
aleloif4dd1912017-06-15 01:55:38 -07001478 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001479 fclose(in_file);
1480}
1481
1482void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001483 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001484 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001485 std::string format_string;
1486 switch (format) {
1487 case kIntFormat:
1488 format_string = "_int";
1489 break;
1490 case kFloatFormat:
1491 format_string = "_float";
1492 break;
1493 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001494 const std::string ref_filename = test::TempFilename(
1495 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1496 const std::string out_filename = test::TempFilename(
1497 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001498 const std::string limited_filename = test::TempFilename(
1499 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1500 const size_t logging_limit_bytes = 100000;
1501 // We expect at least this many bytes in the created logfile.
1502 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001503 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001504 ProcessDebugDump(in_filename, ref_filename, format, -1);
1505 ProcessDebugDump(ref_filename, out_filename, format, -1);
1506 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001507
1508 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1509 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001510 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001511 ASSERT_TRUE(ref_file != NULL);
1512 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001513 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001514 std::unique_ptr<uint8_t[]> ref_bytes;
1515 std::unique_ptr<uint8_t[]> out_bytes;
1516 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001517
1518 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1519 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001520 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001521 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001522 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001523 while (ref_size > 0 && out_size > 0) {
1524 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001525 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001526 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001527 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001528 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001529 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001530 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1531 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001532 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001533 }
1534 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001535 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1536 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001537 EXPECT_NE(0, feof(ref_file));
1538 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001539 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001540 ASSERT_EQ(0, fclose(ref_file));
1541 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001542 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001543 remove(ref_filename.c_str());
1544 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001545 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001546}
1547
pbosc7a65692016-05-06 12:50:04 -07001548TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001549 VerifyDebugDumpTest(kIntFormat);
1550}
1551
pbosc7a65692016-05-06 12:50:04 -07001552TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001553 VerifyDebugDumpTest(kFloatFormat);
1554}
1555#endif
1556
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001557// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001558TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001559 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001560 const std::string filename =
1561 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001562 {
1563 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1564 EXPECT_FALSE(aec_dump);
1565 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001566
1567#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1568 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001569 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001570
aleloif4dd1912017-06-15 01:55:38 -07001571 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1572 EXPECT_TRUE(aec_dump);
1573 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001574 EXPECT_EQ(apm_->kNoError,
1575 apm_->ProcessStream(
1576 frame_.data.data(),
1577 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1578 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001579 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001580 EXPECT_EQ(apm_->kNoError,
1581 apm_->ProcessReverseStream(
1582 revframe_.data.data(),
1583 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1584 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1585 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001586 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001587
1588 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001589 FILE* fid = fopen(filename.c_str(), "r");
1590 ASSERT_TRUE(fid != NULL);
1591
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001592 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001593 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001594 ASSERT_EQ(0, remove(filename.c_str()));
1595#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001596 // Verify the file has NOT been written.
1597 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1598#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1599}
1600
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001601// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001602TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001603 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001604
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001605 const std::string filename =
1606 test::TempFilename(test::OutputPath(), "debug_aec");
Ali Tofigh2ab914c2022-04-13 12:55:15 +02001607 FileWrapper f = FileWrapper::OpenWriteOnly(filename);
Niels Möllere8e4dc42019-06-11 14:04:16 +02001608 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001609
1610#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1611 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001612 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001613
Niels Möllere8e4dc42019-06-11 14:04:16 +02001614 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001615 EXPECT_TRUE(aec_dump);
1616 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001617 EXPECT_EQ(apm_->kNoError,
1618 apm_->ProcessReverseStream(
1619 revframe_.data.data(),
1620 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1621 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1622 revframe_.data.data()));
1623 EXPECT_EQ(apm_->kNoError,
1624 apm_->ProcessStream(
1625 frame_.data.data(),
1626 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1627 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001628 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001629 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001630
1631 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001632 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001633 ASSERT_TRUE(fid != NULL);
1634
1635 // Clean it up.
1636 ASSERT_EQ(0, fclose(fid));
1637 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001638#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1639}
1640
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001641// TODO(andrew): Add a test to process a few frames with different combinations
1642// of enabled components.
1643
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001644TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001645 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001646 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001647
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001648 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001649 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001650 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001651 const int kChannels[] = {1, 2};
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001652 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001653 for (size_t i = 0; i < arraysize(kChannels); i++) {
1654 for (size_t j = 0; j < arraysize(kChannels); j++) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001655 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001656 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001657 test->set_num_reverse_channels(kChannels[i]);
1658 test->set_num_input_channels(kChannels[j]);
1659 test->set_num_output_channels(kChannels[j]);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001660 test->set_sample_rate(sample_rate_hz);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001661 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001662 }
1663 }
1664 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001665#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1666 // To test the extended filter mode.
1667 audioproc::Test* test = ref_data.add_test();
1668 test->set_num_reverse_channels(2);
1669 test->set_num_input_channels(2);
1670 test->set_num_output_channels(2);
1671 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1672 test->set_use_aec_extended_filter(true);
1673#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001674 }
1675
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001676 for (int i = 0; i < ref_data.test_size(); i++) {
1677 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001678
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001679 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001680 // TODO(ajm): We no longer allow different input and output channels. Skip
1681 // these tests for now, but they should be removed from the set.
1682 if (test->num_input_channels() != test->num_output_channels())
1683 continue;
1684
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01001685 apm_ = AudioProcessingBuilderForTesting()
1686 .SetEchoDetector(CreateEchoDetector())
1687 .Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001688 AudioProcessing::Config apm_config = apm_->GetConfig();
1689 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1690 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001691
1692 EnableAllComponents();
1693
Jonas Olssona4d87372019-07-05 19:08:33 +02001694 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001695 static_cast<size_t>(test->num_input_channels()),
1696 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001697 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001698
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001699 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001700 int analog_level = 127;
1701 int analog_level_average = 0;
1702 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001703#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001704 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001705#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001706
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001707 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001708 EXPECT_EQ(
1709 apm_->kNoError,
1710 apm_->ProcessReverseStream(
1711 revframe_.data.data(),
1712 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1713 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1714 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001715
1716 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001717 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001718
Per Åhgren2507f8c2020-03-19 12:33:29 +01001719 EXPECT_EQ(apm_->kNoError,
1720 apm_->ProcessStream(
1721 frame_.data.data(),
1722 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1723 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001724 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001725
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001726 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001727 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001728 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001729
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001730 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001731
Sam Zackrisson41478c72019-10-15 10:10:26 +02001732 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001733 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001734 AudioProcessingStats stats = apm_->GetStatistics();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001735
Per Åhgren2507f8c2020-03-19 12:33:29 +01001736 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001737 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001738 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001739 ASSERT_EQ(frame_size, write_count);
1740
1741 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001742 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001743 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001744
1745#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1746 const int kStatsAggregationFrameNum = 100; // 1 second.
1747 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001748 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001749 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001750
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001751 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001752 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001753 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001754 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001755 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001756 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001757 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001758 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001759
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001760 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001761 const audioproc::Test::EchoMetrics& reference =
1762 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001763 constexpr float kEpsilon = 0.01;
1764 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1765 EXPECT_NEAR(echo_return_loss_enhancement,
1766 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001767 EXPECT_NEAR(residual_echo_likelihood,
1768 reference.residual_echo_likelihood(), kEpsilon);
1769 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1770 reference.residual_echo_likelihood_recent_max(),
1771 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001772 ++stats_index;
1773 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001774 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1775 message_echo->set_echo_return_loss(echo_return_loss);
1776 message_echo->set_echo_return_loss_enhancement(
1777 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001778 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1779 message_echo->set_residual_echo_likelihood_recent_max(
1780 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001781 }
1782 }
1783#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001784 }
1785 max_output_average /= frame_count;
1786 analog_level_average /= frame_count;
1787
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001788 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001789 const int kIntNear = 1;
Alessio Bazzica1db0a262022-02-15 14:18:09 +00001790 // All numbers being consistently higher on N7 compare to the reference
1791 // data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001792 // TODO(bjornv): If we start getting more of these offsets on Android we
1793 // should consider a different approach. Either using one slack for all,
1794 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001795#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001796 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001797 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001798#else
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001799 const int kMaxOutputAverageOffset = 0;
1800 const int kMaxOutputAverageNear = kIntNear;
1801#endif
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001802 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001803 EXPECT_NEAR(test->max_output_average(),
1804 max_output_average - kMaxOutputAverageOffset,
1805 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001806 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001807 test->set_analog_level_average(analog_level_average);
1808 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001809 }
1810
1811 rewind(far_file_);
1812 rewind(near_file_);
1813 }
1814
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001815 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001816 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001817 }
1818}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001819
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001820// Compares the reference and test arrays over a region around the expected
1821// delay. Finds the highest SNR in that region and adds the variance and squared
1822// error results to the supplied accumulators.
1823void UpdateBestSNR(const float* ref,
1824 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001825 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001826 int expected_delay,
1827 double* variance_acc,
1828 double* sq_error_acc) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001829 RTC_CHECK_LT(expected_delay, length)
1830 << "delay greater than signal length, cannot compute SNR";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001831 double best_snr = std::numeric_limits<double>::min();
1832 double best_variance = 0;
1833 double best_sq_error = 0;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001834 // Search over a region of nine samples around the expected delay.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001835 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1836 ++delay) {
1837 double sq_error = 0;
1838 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001839 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001840 double error = test[i + delay] - ref[i];
1841 sq_error += error * error;
1842 variance += ref[i] * ref[i];
1843 }
1844
1845 if (sq_error == 0) {
1846 *variance_acc += variance;
1847 return;
1848 }
1849 double snr = variance / sq_error;
1850 if (snr > best_snr) {
1851 best_snr = snr;
1852 best_variance = variance;
1853 best_sq_error = sq_error;
1854 }
1855 }
1856
1857 *variance_acc += best_variance;
1858 *sq_error_acc += best_sq_error;
1859}
1860
1861// Used to test a multitude of sample rate and channel combinations. It works
1862// by first producing a set of reference files (in SetUpTestCase) that are
1863// assumed to be correct, as the used parameters are verified by other tests
1864// in this collection. Primarily the reference files are all produced at
1865// "native" rates which do not involve any resampling.
1866
1867// Each test pass produces an output file with a particular format. The output
1868// is matched against the reference file closest to its internal processing
1869// format. If necessary the output is resampled back to its process format.
1870// Due to the resampling distortion, we don't expect identical results, but
1871// enforce SNR thresholds which vary depending on the format. 0 is a special
1872// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001873typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001874class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001875 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001876 public:
1877 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001878 : input_rate_(std::get<0>(GetParam())),
1879 output_rate_(std::get<1>(GetParam())),
1880 reverse_input_rate_(std::get<2>(GetParam())),
1881 reverse_output_rate_(std::get<3>(GetParam())),
1882 expected_snr_(std::get<4>(GetParam())),
1883 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001884
1885 virtual ~AudioProcessingTest() {}
1886
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001887 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001888 // Create all needed output reference files.
Peter Kasting69558702016-01-12 16:26:35 -08001889 const size_t kNumChannels[] = {1, 2};
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001890 for (size_t i = 0; i < arraysize(kProcessSampleRates); ++i) {
pkasting25702cb2016-01-08 13:50:27 -08001891 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1892 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001893 // The reference files always have matching input and output channels.
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001894 ProcessFormat(kProcessSampleRates[i], kProcessSampleRates[i],
1895 kProcessSampleRates[i], kProcessSampleRates[i],
1896 kNumChannels[j], kNumChannels[j], kNumChannels[k],
1897 kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001898 }
1899 }
1900 }
1901 }
1902
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001903 void TearDown() {
1904 // Remove "out" files after each test.
1905 ClearTempOutFiles();
1906 }
1907
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001908 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001909
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001910 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02001911 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07001912 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001913 static void ProcessFormat(int input_rate,
1914 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001915 int reverse_input_rate,
1916 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001917 size_t num_input_channels,
1918 size_t num_output_channels,
1919 size_t num_reverse_input_channels,
1920 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02001921 const std::string& output_file_prefix) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001922 AudioProcessing::Config apm_config;
Per Åhgren0695df12020-01-13 14:43:13 +01001923 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001924 rtc::scoped_refptr<AudioProcessing> ap =
1925 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001926
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001927 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001928
ekmeyerson60d9b332015-08-14 10:35:55 -07001929 ProcessingConfig processing_config = {
1930 {{input_rate, num_input_channels},
1931 {output_rate, num_output_channels},
1932 {reverse_input_rate, num_reverse_input_channels},
1933 {reverse_output_rate, num_reverse_output_channels}}};
1934 ap->Initialize(processing_config);
1935
1936 FILE* far_file =
1937 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001938 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02001939 FILE* out_file = fopen(
1940 OutputFilePath(
1941 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1942 reverse_output_rate, num_input_channels, num_output_channels,
1943 num_reverse_input_channels, num_reverse_output_channels, kForward)
1944 .c_str(),
1945 "wb");
1946 FILE* rev_out_file = fopen(
1947 OutputFilePath(
1948 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1949 reverse_output_rate, num_input_channels, num_output_channels,
1950 num_reverse_input_channels, num_reverse_output_channels, kReverse)
1951 .c_str(),
1952 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001953 ASSERT_TRUE(far_file != NULL);
1954 ASSERT_TRUE(near_file != NULL);
1955 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07001956 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001957
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001958 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001959 num_input_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001960 ChannelBuffer<float> rev_cb(
1961 AudioProcessing::GetFrameSize(reverse_input_rate),
1962 num_reverse_input_channels);
1963 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001964 num_output_channels);
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02001965 ChannelBuffer<float> rev_out_cb(
1966 AudioProcessing::GetFrameSize(reverse_output_rate),
1967 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001968
1969 // Temporary buffers.
1970 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07001971 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
1972 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08001973 std::unique_ptr<float[]> float_data(new float[max_length]);
1974 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001975
1976 int analog_level = 127;
1977 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
1978 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07001979 EXPECT_NOERR(ap->ProcessReverseStream(
1980 rev_cb.channels(), processing_config.reverse_input_stream(),
1981 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001982
1983 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001984 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001985
1986 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001987 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
1988 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001989
ekmeyerson60d9b332015-08-14 10:35:55 -07001990 // Dump forward output to file.
1991 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001992 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08001993 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07001994
Jonas Olssona4d87372019-07-05 19:08:33 +02001995 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
1996 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001997
ekmeyerson60d9b332015-08-14 10:35:55 -07001998 // Dump reverse output to file.
1999 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2000 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002001 size_t rev_out_length =
2002 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002003
Jonas Olssona4d87372019-07-05 19:08:33 +02002004 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2005 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002006
Sam Zackrisson41478c72019-10-15 10:10:26 +02002007 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002008 }
2009 fclose(far_file);
2010 fclose(near_file);
2011 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002012 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002013 }
2014
2015 protected:
2016 int input_rate_;
2017 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002018 int reverse_input_rate_;
2019 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002020 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002021 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002022};
2023
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002024TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002025 struct ChannelFormat {
2026 int num_input;
2027 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002028 int num_reverse_input;
2029 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002030 };
2031 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002032 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2033 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002034 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002035
pkasting25702cb2016-01-08 13:50:27 -08002036 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002037 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2038 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2039 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002040
ekmeyerson60d9b332015-08-14 10:35:55 -07002041 // Verify output for both directions.
2042 std::vector<StreamDirection> stream_directions;
2043 stream_directions.push_back(kForward);
2044 stream_directions.push_back(kReverse);
2045 for (StreamDirection file_direction : stream_directions) {
2046 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2047 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2048 const int out_num =
2049 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2050 const double expected_snr =
2051 file_direction ? expected_reverse_snr_ : expected_snr_;
2052
2053 const int min_ref_rate = std::min(in_rate, out_rate);
2054 int ref_rate;
ekmeyerson60d9b332015-08-14 10:35:55 -07002055 if (min_ref_rate > 32000) {
2056 ref_rate = 48000;
2057 } else if (min_ref_rate > 16000) {
2058 ref_rate = 32000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002059 } else {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002060 ref_rate = 16000;
ekmeyerson60d9b332015-08-14 10:35:55 -07002061 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002062
ekmeyerson60d9b332015-08-14 10:35:55 -07002063 FILE* out_file = fopen(
2064 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2065 reverse_output_rate_, cf[i].num_input,
2066 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002067 cf[i].num_reverse_output, file_direction)
2068 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002069 "rb");
2070 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002071 FILE* ref_file =
2072 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2073 cf[i].num_output, cf[i].num_output,
2074 cf[i].num_reverse_output,
2075 cf[i].num_reverse_output, file_direction)
2076 .c_str(),
2077 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002078 ASSERT_TRUE(out_file != NULL);
2079 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002080
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002081 const size_t ref_length =
2082 AudioProcessing::GetFrameSize(ref_rate) * out_num;
2083 const size_t out_length =
2084 AudioProcessing::GetFrameSize(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002085 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002086 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002087 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002088 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002089 // Data from the resampled output, in case the reference and output rates
2090 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002091 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002092
ekmeyerson60d9b332015-08-14 10:35:55 -07002093 PushResampler<float> resampler;
2094 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002095
ekmeyerson60d9b332015-08-14 10:35:55 -07002096 // Compute the resampling delay of the output relative to the reference,
2097 // to find the region over which we should search for the best SNR.
2098 float expected_delay_sec = 0;
2099 if (in_rate != ref_rate) {
2100 // Input resampling delay.
2101 expected_delay_sec +=
2102 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2103 }
2104 if (out_rate != ref_rate) {
2105 // Output resampling delay.
2106 expected_delay_sec +=
2107 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2108 // Delay of converting the output back to its processing rate for
2109 // testing.
2110 expected_delay_sec +=
2111 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2112 }
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002113 // The delay is multiplied by the number of channels because
2114 // UpdateBestSNR() computes the SNR over interleaved data without taking
2115 // channels into account.
ekmeyerson60d9b332015-08-14 10:35:55 -07002116 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002117 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002118
ekmeyerson60d9b332015-08-14 10:35:55 -07002119 double variance = 0;
2120 double sq_error = 0;
2121 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2122 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2123 float* out_ptr = out_data.get();
2124 if (out_rate != ref_rate) {
2125 // Resample the output back to its internal processing rate if
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002126 // necessary.
pkasting25702cb2016-01-08 13:50:27 -08002127 ASSERT_EQ(ref_length,
2128 static_cast<size_t>(resampler.Resample(
2129 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002130 out_ptr = cmp_data.get();
2131 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002132
Artem Titov0b489302021-07-28 20:50:03 +02002133 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002134 // SNR of reference vs output.
2135 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2136 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002137 }
2138
ekmeyerson60d9b332015-08-14 10:35:55 -07002139 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2140 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2141 << cf[i].num_input << ", " << cf[i].num_output << ", "
2142 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2143 << ", " << file_direction << "): ";
2144 if (sq_error > 0) {
2145 double snr = 10 * log10(variance / sq_error);
2146 EXPECT_GE(snr, expected_snr);
2147 EXPECT_NE(0, expected_snr);
2148 std::cout << "SNR=" << snr << " dB" << std::endl;
2149 } else {
aluebs776593b2016-03-15 14:04:58 -07002150 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002151 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002152
ekmeyerson60d9b332015-08-14 10:35:55 -07002153 fclose(out_file);
2154 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002155 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002156 }
2157}
2158
2159#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002160INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002161 CommonFormats,
2162 AudioProcessingTest,
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002163 // Internal processing rates and the particularly common sample rate 44100
2164 // Hz are tested in a grid of combinations (capture in, render in, out).
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002165 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2166 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2167 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2168 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2169 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2170 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2171 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2172 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2173 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2174 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2175 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2176 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002177
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002178 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2179 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2180 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2181 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2182 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2183 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2184 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2185 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2186 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2187 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2188 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2189 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002190
Per Åhgrenc0424252019-12-10 13:04:15 +01002191 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2192 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2193 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002194 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2195 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2196 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2197 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2198 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002199 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002200 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2201 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2202 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002203
Per Åhgrenc0424252019-12-10 13:04:15 +01002204 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2205 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2206 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002207 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2208 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2209 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2210 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2211 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2212 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2213 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002214 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002215 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2216
2217 // Other sample rates are not tested exhaustively, to keep
2218 // the test runtime manageable.
2219 //
2220 // Testing most other sample rates logged by Chrome UMA:
2221 // - WebRTC.AudioInputSampleRate
2222 // - WebRTC.AudioOutputSampleRate
2223 // ApmConfiguration.HandlingOfRateCombinations covers
2224 // remaining sample rates.
2225 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2226 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2227 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2228 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2229 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002230
2231#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002232INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002233 CommonFormats,
2234 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002235 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2236 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2237 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002238 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2239 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2240 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002241 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2242 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2243 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002244 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2245 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2246 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002247
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002248 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2249 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2250 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2251 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2252 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2253 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002254 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2255 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2256 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2257 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2258 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2259 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002260
Per Åhgrenc0424252019-12-10 13:04:15 +01002261 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2262 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2263 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002264 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2265 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2266 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002267 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002268 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002269 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002270 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2271 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2272 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002273
Per Åhgrenc0424252019-12-10 13:04:15 +01002274 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2275 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2276 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002277 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2278 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2279 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002280 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002281 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002282 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002283 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2284 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002285 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2286
2287 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2288 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2289 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2290 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2291 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002292#endif
2293
Per Åhgren3e8bf282019-08-29 23:38:40 +02002294// Produces a scoped trace debug output.
2295std::string ProduceDebugText(int render_input_sample_rate_hz,
2296 int render_output_sample_rate_hz,
2297 int capture_input_sample_rate_hz,
2298 int capture_output_sample_rate_hz,
2299 size_t render_input_num_channels,
2300 size_t render_output_num_channels,
2301 size_t capture_input_num_channels,
2302 size_t capture_output_num_channels) {
2303 rtc::StringBuilder ss;
2304 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002305 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002306 << render_input_sample_rate_hz
2307 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002308 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002309 << render_output_sample_rate_hz
2310 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002311 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002312 << capture_input_sample_rate_hz
2313 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002314 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002315 << capture_output_sample_rate_hz
2316 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002317 "\nNumber of channels:"
2318 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002319 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002320 << "\n Render output: " << render_output_num_channels
2321 << "\n Capture input: " << capture_input_num_channels
2322 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002323 return ss.Release();
2324}
2325
2326// Validates that running the audio processing module using various combinations
2327// of sample rates and number of channels works as intended.
2328void RunApmRateAndChannelTest(
2329 rtc::ArrayView<const int> sample_rates_hz,
2330 rtc::ArrayView<const int> render_channel_counts,
2331 rtc::ArrayView<const int> capture_channel_counts) {
Per Åhgren3e8bf282019-08-29 23:38:40 +02002332 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002333 apm_config.pipeline.multi_channel_render = true;
2334 apm_config.pipeline.multi_channel_capture = true;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002335 apm_config.echo_canceller.enabled = true;
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002336 rtc::scoped_refptr<AudioProcessing> apm =
2337 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002338
2339 StreamConfig render_input_stream_config;
2340 StreamConfig render_output_stream_config;
2341 StreamConfig capture_input_stream_config;
2342 StreamConfig capture_output_stream_config;
2343
2344 std::vector<float> render_input_frame_channels;
2345 std::vector<float*> render_input_frame;
2346 std::vector<float> render_output_frame_channels;
2347 std::vector<float*> render_output_frame;
2348 std::vector<float> capture_input_frame_channels;
2349 std::vector<float*> capture_input_frame;
2350 std::vector<float> capture_output_frame_channels;
2351 std::vector<float*> capture_output_frame;
2352
2353 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2354 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2355 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2356 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2357 for (size_t render_input_num_channels : render_channel_counts) {
2358 for (size_t capture_input_num_channels : capture_channel_counts) {
2359 size_t render_output_num_channels = render_input_num_channels;
2360 size_t capture_output_num_channels = capture_input_num_channels;
2361 auto populate_audio_frame = [](int sample_rate_hz,
2362 size_t num_channels,
2363 StreamConfig* cfg,
2364 std::vector<float>* channels_data,
2365 std::vector<float*>* frame_data) {
2366 cfg->set_sample_rate_hz(sample_rate_hz);
2367 cfg->set_num_channels(num_channels);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002368
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002369 size_t max_frame_size =
2370 AudioProcessing::GetFrameSize(sample_rate_hz);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002371 channels_data->resize(num_channels * max_frame_size);
2372 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2373 frame_data->resize(num_channels);
2374 for (size_t channel = 0; channel < num_channels; ++channel) {
2375 (*frame_data)[channel] =
2376 &(*channels_data)[channel * max_frame_size];
2377 }
2378 };
2379
2380 populate_audio_frame(
2381 render_input_sample_rate_hz, render_input_num_channels,
2382 &render_input_stream_config, &render_input_frame_channels,
2383 &render_input_frame);
2384 populate_audio_frame(
2385 render_output_sample_rate_hz, render_output_num_channels,
2386 &render_output_stream_config, &render_output_frame_channels,
2387 &render_output_frame);
2388 populate_audio_frame(
2389 capture_input_sample_rate_hz, capture_input_num_channels,
2390 &capture_input_stream_config, &capture_input_frame_channels,
2391 &capture_input_frame);
2392 populate_audio_frame(
2393 capture_output_sample_rate_hz, capture_output_num_channels,
2394 &capture_output_stream_config, &capture_output_frame_channels,
2395 &capture_output_frame);
2396
2397 for (size_t frame = 0; frame < 2; ++frame) {
2398 SCOPED_TRACE(ProduceDebugText(
2399 render_input_sample_rate_hz, render_output_sample_rate_hz,
2400 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2401 render_input_num_channels, render_output_num_channels,
2402 render_input_num_channels, capture_output_num_channels));
2403
2404 int result = apm->ProcessReverseStream(
2405 &render_input_frame[0], render_input_stream_config,
2406 render_output_stream_config, &render_output_frame[0]);
2407 EXPECT_EQ(result, AudioProcessing::kNoError);
2408 result = apm->ProcessStream(
2409 &capture_input_frame[0], capture_input_stream_config,
2410 capture_output_stream_config, &capture_output_frame[0]);
2411 EXPECT_EQ(result, AudioProcessing::kNoError);
2412 }
2413 }
2414 }
2415 }
2416 }
2417 }
2418 }
2419}
2420
Alessio Bazzica3438a932020-10-14 12:47:50 +02002421constexpr void Toggle(bool& b) {
2422 b ^= true;
2423}
2424
niklase@google.com470e71d2011-07-07 08:21:25 +00002425} // namespace
peahc19f3122016-10-07 14:54:10 -07002426
Alessio Bazzicac054e782018-04-16 12:10:09 +02002427TEST(RuntimeSettingTest, TestDefaultCtor) {
2428 auto s = AudioProcessing::RuntimeSetting();
2429 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2430}
2431
Alessio Bazzicac054e782018-04-16 12:10:09 +02002432TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2433 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2434 auto s = AudioProcessing::RuntimeSetting();
2435 ASSERT_TRUE(q.Insert(&s));
2436 ASSERT_TRUE(q.Remove(&s));
2437 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2438}
2439
Sam Zackrisson0beac582017-09-25 12:04:02 +02002440TEST(ApmConfiguration, EnablePostProcessing) {
2441 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002442 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002443 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002444 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002445 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002446 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002447 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002448 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002449 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002450
Per Åhgren2507f8c2020-03-19 12:33:29 +01002451 Int16FrameData audio;
2452 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002453 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2454
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002455 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002456 apm->ProcessStream(audio.data.data(),
2457 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2458 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002459 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002460}
2461
Alex Loiko5825aa62017-12-18 16:02:40 +01002462TEST(ApmConfiguration, EnablePreProcessing) {
2463 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002464 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002465 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002466 auto mock_pre_processor =
2467 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002468 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002469 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002470 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002471 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002472
Per Åhgren2507f8c2020-03-19 12:33:29 +01002473 Int16FrameData audio;
2474 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002475 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2476
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002477 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002478 apm->ProcessReverseStream(
2479 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2480 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2481 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002482}
2483
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002484TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2485 // Verify that apm uses a capture analyzer if one is provided.
2486 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002487 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002488 auto mock_capture_analyzer =
2489 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2490 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002491 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002492 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2493 .Create();
2494
Per Åhgren2507f8c2020-03-19 12:33:29 +01002495 Int16FrameData audio;
2496 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002497 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2498
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002499 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002500 apm->ProcessStream(audio.data.data(),
2501 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2502 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002503 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002504}
2505
Alex Loiko73ec0192018-05-15 10:52:28 +02002506TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2507 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002508 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002509 auto mock_pre_processor =
2510 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2511 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002512 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002513 .SetRenderPreProcessing(std::move(mock_pre_processor))
2514 .Create();
2515 apm->SetRuntimeSetting(
2516 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2517
2518 // RuntimeSettings forwarded during 'Process*Stream' calls.
2519 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002520 Int16FrameData audio;
2521 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002522 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2523
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002524 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2525 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002526 apm->ProcessReverseStream(
2527 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2528 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2529 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002530}
2531
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002532class MyEchoControlFactory : public EchoControlFactory {
2533 public:
2534 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2535 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002536 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2537 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002538 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2539 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002540 return std::unique_ptr<EchoControl>(ec);
2541 }
Per Åhgrence202a02019-09-02 17:01:19 +02002542
2543 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002544 int num_render_channels,
2545 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002546 return Create(sample_rate_hz);
2547 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002548};
2549
2550TEST(ApmConfiguration, EchoControlInjection) {
2551 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002552 std::unique_ptr<EchoControlFactory> echo_control_factory(
2553 new MyEchoControlFactory());
2554
Alex Loiko5825aa62017-12-18 16:02:40 +01002555 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002556 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002557 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002558 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002559
Per Åhgren2507f8c2020-03-19 12:33:29 +01002560 Int16FrameData audio;
2561 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002562 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002563 apm->ProcessStream(audio.data.data(),
2564 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2565 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002566 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002567 apm->ProcessReverseStream(
2568 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2569 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2570 audio.data.data());
2571 apm->ProcessStream(audio.data.data(),
2572 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2573 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002574 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002575}
Ivo Creusenae026092017-11-20 13:07:16 +01002576
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002577TEST(ApmConfiguration, EchoDetectorInjection) {
2578 using ::testing::_;
2579 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2580 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2581 EXPECT_CALL(*mock_echo_detector,
2582 Initialize(/*capture_sample_rate_hz=*/16000, _,
2583 /*render_sample_rate_hz=*/16000, _))
2584 .Times(1);
Niels Möller4f776ac2021-07-02 11:30:54 +02002585 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002586 AudioProcessingBuilderForTesting()
2587 .SetEchoDetector(mock_echo_detector)
2588 .Create();
2589
2590 // The echo detector is included in processing when enabled.
2591 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2592 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2593 EXPECT_EQ(render_audio.size(), 160u);
2594 });
2595 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2596 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2597 EXPECT_EQ(capture_audio.size(), 160u);
2598 });
2599 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2600
2601 Int16FrameData frame;
2602 frame.num_channels = 1;
2603 SetFrameSampleRate(&frame, 16000);
2604
2605 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2606 StreamConfig(16000, 1), frame.data.data());
2607 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2608 StreamConfig(16000, 1), frame.data.data());
2609
2610 // When processing rates change, the echo detector is also reinitialized to
2611 // match those.
2612 EXPECT_CALL(*mock_echo_detector,
2613 Initialize(/*capture_sample_rate_hz=*/48000, _,
2614 /*render_sample_rate_hz=*/16000, _))
2615 .Times(1);
2616 EXPECT_CALL(*mock_echo_detector,
2617 Initialize(/*capture_sample_rate_hz=*/48000, _,
2618 /*render_sample_rate_hz=*/48000, _))
2619 .Times(1);
2620 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2621 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2622 EXPECT_EQ(render_audio.size(), 480u);
2623 });
2624 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2625 .Times(2)
2626 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2627 EXPECT_EQ(capture_audio.size(), 480u);
2628 });
2629 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2630
2631 SetFrameSampleRate(&frame, 48000);
2632 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2633 StreamConfig(48000, 1), frame.data.data());
2634 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2635 StreamConfig(48000, 1), frame.data.data());
2636 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2637 StreamConfig(48000, 1), frame.data.data());
2638}
2639
2640rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2641 // Enable residual echo detection, for stats.
2642 rtc::scoped_refptr<AudioProcessing> apm =
2643 AudioProcessingBuilderForTesting()
2644 .SetEchoDetector(CreateEchoDetector())
2645 .Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002646 if (!apm) {
2647 return apm;
2648 }
2649
2650 ProcessingConfig processing_config = {
2651 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2652
2653 if (apm->Initialize(processing_config) != 0) {
2654 return nullptr;
2655 }
2656
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002657 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002658 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002659 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002660 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002661 apm_config.gain_controller2.enabled = false;
2662 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002663 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002664 apm_config.noise_suppression.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002665 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002666 return apm;
2667}
2668
2669#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2670#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2671#else
2672#define MAYBE_ApmStatistics ApmStatistics
2673#endif
2674
Per Åhgren8607f842019-04-12 22:02:26 +02002675TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2676 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002677 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002678 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002679 AudioProcessing::Config apm_config;
2680 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002681 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002682
2683 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002684 Int16FrameData frame;
2685 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002686 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002687
2688 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002689 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002690 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2691 ptr[i] = 10000 * ((i % 3) - 1);
2692 }
2693
2694 // Do some processing.
2695 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002696 EXPECT_EQ(apm->ProcessReverseStream(
2697 frame.data.data(),
2698 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2699 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2700 frame.data.data()),
2701 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002702 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002703 EXPECT_EQ(apm->ProcessStream(
2704 frame.data.data(),
2705 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2706 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002707 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002708 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002709 }
2710
2711 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002712 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002713 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002714 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002715 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2716 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002717 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002718 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2719 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002720 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002721 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002722 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002723 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002724}
2725
2726TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2727 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002728 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002729 ASSERT_TRUE(apm);
2730
2731 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002732 Int16FrameData frame;
2733 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002734 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002735
2736 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002737 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002738 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2739 ptr[i] = 10000 * ((i % 3) - 1);
2740 }
2741
2742 // Do some processing.
2743 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002744 EXPECT_EQ(apm->ProcessReverseStream(
2745 frame.data.data(),
2746 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2747 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2748 frame.data.data()),
2749 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002750 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002751 EXPECT_EQ(apm->ProcessStream(
2752 frame.data.data(),
2753 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2754 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002755 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002756 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002757 }
2758
2759 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002760 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002761 // We expect only the residual echo detector statistics to be set and have a
2762 // sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002763 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2764 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2765 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2766 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2767 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2768 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2769 EXPECT_FALSE(stats.echo_return_loss.has_value());
2770 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002771}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002772
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002773TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002774 ProcessingConfig processing_config = {
2775 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002776
2777 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002778 Int16FrameData frame;
2779 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002780 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2781
2782 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002783 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002784 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2785 ptr[i] = 10000 * ((i % 3) - 1);
2786 }
2787
Niels Möller4f776ac2021-07-02 11:30:54 +02002788 rtc::scoped_refptr<AudioProcessing> apm =
2789 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002790 apm->Initialize(processing_config);
2791
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002792 // No metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002793 EXPECT_EQ(
2794 apm->ProcessStream(frame.data.data(),
2795 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2796 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002797 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002798 0);
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002799 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002800}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002801
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002802TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2803 rtc::scoped_refptr<AudioProcessing> apm =
2804 AudioProcessingBuilderForTesting().Create();
2805 Int16FrameData frame;
2806 frame.num_channels = 1;
2807 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2808 ASSERT_EQ(
2809 apm->ProcessStream(frame.data.data(),
2810 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2811 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2812 frame.data.data()),
2813 0);
2814 // Echo detector is disabled by default, no stats reported.
2815 AudioProcessingStats stats = apm->GetStatistics();
2816 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2817 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2818}
2819
2820TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2821 // Create APM with an echo detector injected.
2822 rtc::scoped_refptr<AudioProcessing> apm =
2823 AudioProcessingBuilderForTesting()
2824 .SetEchoDetector(CreateEchoDetector())
2825 .Create();
2826 Int16FrameData frame;
2827 frame.num_channels = 1;
2828 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2829 // Echo detector enabled: Report stats.
2830 ASSERT_EQ(
2831 apm->ProcessStream(frame.data.data(),
2832 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2833 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2834 frame.data.data()),
2835 0);
2836 AudioProcessingStats stats = apm->GetStatistics();
2837 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2838 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2839}
2840
Per Åhgren3e8bf282019-08-29 23:38:40 +02002841TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2842 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2843 std::array<int, 2> render_channel_counts = {1, 7};
2844 std::array<int, 2> capture_channel_counts = {1, 7};
2845 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2846 capture_channel_counts);
2847}
2848
2849TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2850 std::array<int, 1> sample_rates_hz = {48000};
2851 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2852 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2853 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2854 capture_channel_counts);
2855}
2856
2857TEST(ApmConfiguration, HandlingOfRateCombinations) {
Sam Zackrisson3bd444f2022-08-03 14:37:00 +02002858 // Test rates <= 96000 logged by Chrome UMA:
2859 // - WebRTC.AudioInputSampleRate
2860 // - WebRTC.AudioOutputSampleRate
2861 // Higher rates are tested in AudioProcessingTest.Format, to keep the number
2862 // of combinations in this test manageable.
2863 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2864 44100, 48000, 88200, 96000};
Per Åhgren3e8bf282019-08-29 23:38:40 +02002865 std::array<int, 1> render_channel_counts = {2};
2866 std::array<int, 1> capture_channel_counts = {2};
2867 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2868 capture_channel_counts);
2869}
2870
Yves Gerey1fce3f82019-12-05 17:45:31 +01002871TEST(ApmConfiguration, SelfAssignment) {
2872 // At some point memory sanitizer was complaining about self-assigment.
2873 // Make sure we don't regress.
2874 AudioProcessing::Config config;
2875 AudioProcessing::Config* config2 = &config;
2876 *config2 = *config2; // Workaround -Wself-assign-overloaded
2877 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2878}
2879
Alessio Bazzica3438a932020-10-14 12:47:50 +02002880TEST(AudioProcessing, GainController1ConfigEqual) {
2881 AudioProcessing::Config::GainController1 a;
2882 AudioProcessing::Config::GainController1 b;
2883 EXPECT_EQ(a, b);
2884
2885 Toggle(a.enabled);
2886 b.enabled = a.enabled;
2887 EXPECT_EQ(a, b);
2888
2889 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2890 b.mode = a.mode;
2891 EXPECT_EQ(a, b);
2892
2893 a.target_level_dbfs++;
2894 b.target_level_dbfs = a.target_level_dbfs;
2895 EXPECT_EQ(a, b);
2896
2897 a.compression_gain_db++;
2898 b.compression_gain_db = a.compression_gain_db;
2899 EXPECT_EQ(a, b);
2900
2901 Toggle(a.enable_limiter);
2902 b.enable_limiter = a.enable_limiter;
2903 EXPECT_EQ(a, b);
2904
Alessio Bazzica3438a932020-10-14 12:47:50 +02002905 auto& a_analog = a.analog_gain_controller;
2906 auto& b_analog = b.analog_gain_controller;
2907
2908 Toggle(a_analog.enabled);
2909 b_analog.enabled = a_analog.enabled;
2910 EXPECT_EQ(a, b);
2911
2912 a_analog.startup_min_volume++;
2913 b_analog.startup_min_volume = a_analog.startup_min_volume;
2914 EXPECT_EQ(a, b);
2915
2916 a_analog.clipped_level_min++;
2917 b_analog.clipped_level_min = a_analog.clipped_level_min;
2918 EXPECT_EQ(a, b);
2919
Alessio Bazzica3438a932020-10-14 12:47:50 +02002920 Toggle(a_analog.enable_digital_adaptive);
2921 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2922 EXPECT_EQ(a, b);
2923}
2924
2925// Checks that one differing parameter is sufficient to make two configs
2926// different.
2927TEST(AudioProcessing, GainController1ConfigNotEqual) {
2928 AudioProcessing::Config::GainController1 a;
2929 const AudioProcessing::Config::GainController1 b;
2930
2931 Toggle(a.enabled);
2932 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002933 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002934
2935 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2936 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002937 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002938
2939 a.target_level_dbfs++;
2940 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002941 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002942
2943 a.compression_gain_db++;
2944 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002945 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002946
2947 Toggle(a.enable_limiter);
2948 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002949 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002950
Alessio Bazzica3438a932020-10-14 12:47:50 +02002951 auto& a_analog = a.analog_gain_controller;
2952 const auto& b_analog = b.analog_gain_controller;
2953
2954 Toggle(a_analog.enabled);
2955 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002956 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002957
2958 a_analog.startup_min_volume++;
2959 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002960 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002961
2962 a_analog.clipped_level_min++;
2963 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002964 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002965
Alessio Bazzica3438a932020-10-14 12:47:50 +02002966 Toggle(a_analog.enable_digital_adaptive);
2967 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002968 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002969}
2970
2971TEST(AudioProcessing, GainController2ConfigEqual) {
2972 AudioProcessing::Config::GainController2 a;
2973 AudioProcessing::Config::GainController2 b;
2974 EXPECT_EQ(a, b);
2975
2976 Toggle(a.enabled);
2977 b.enabled = a.enabled;
2978 EXPECT_EQ(a, b);
2979
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002980 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002981 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
2982 EXPECT_EQ(a, b);
2983
2984 auto& a_adaptive = a.adaptive_digital;
2985 auto& b_adaptive = b.adaptive_digital;
2986
2987 Toggle(a_adaptive.enabled);
2988 b_adaptive.enabled = a_adaptive.enabled;
2989 EXPECT_EQ(a, b);
2990
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002991 Toggle(a_adaptive.dry_run);
2992 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002993 EXPECT_EQ(a, b);
2994
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02002995 a_adaptive.headroom_db += 1.0f;
2996 b_adaptive.headroom_db = a_adaptive.headroom_db;
2997 EXPECT_EQ(a, b);
2998
2999 a_adaptive.max_gain_db += 1.0f;
3000 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3001 EXPECT_EQ(a, b);
3002
3003 a_adaptive.initial_gain_db += 1.0f;
3004 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3005 EXPECT_EQ(a, b);
3006
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003007 a_adaptive.vad_reset_period_ms++;
3008 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003009 EXPECT_EQ(a, b);
3010
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003011 a_adaptive.adjacent_speech_frames_threshold++;
3012 b_adaptive.adjacent_speech_frames_threshold =
3013 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003014 EXPECT_EQ(a, b);
3015
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003016 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003017 b_adaptive.max_gain_change_db_per_second =
3018 a_adaptive.max_gain_change_db_per_second;
3019 EXPECT_EQ(a, b);
3020
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003021 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003022 b_adaptive.max_output_noise_level_dbfs =
3023 a_adaptive.max_output_noise_level_dbfs;
3024 EXPECT_EQ(a, b);
3025}
3026
3027// Checks that one differing parameter is sufficient to make two configs
3028// different.
3029TEST(AudioProcessing, GainController2ConfigNotEqual) {
3030 AudioProcessing::Config::GainController2 a;
3031 const AudioProcessing::Config::GainController2 b;
3032
3033 Toggle(a.enabled);
3034 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003035 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003036
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003037 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003038 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003039 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003040
3041 auto& a_adaptive = a.adaptive_digital;
3042 const auto& b_adaptive = b.adaptive_digital;
3043
3044 Toggle(a_adaptive.enabled);
3045 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003046 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003047
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003048 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003049 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003050 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003051
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003052 a_adaptive.headroom_db += 1.0f;
3053 EXPECT_NE(a, b);
3054 a_adaptive = b_adaptive;
3055
3056 a_adaptive.max_gain_db += 1.0f;
3057 EXPECT_NE(a, b);
3058 a_adaptive = b_adaptive;
3059
3060 a_adaptive.initial_gain_db += 1.0f;
3061 EXPECT_NE(a, b);
3062 a_adaptive = b_adaptive;
3063
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003064 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003065 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003066 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003067
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003068 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003069 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003070 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003071
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003072 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003073 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003074 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003075
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003076 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003077 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003078 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003079}
3080
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003081} // namespace webrtc