blob: 96e2d846d93ae6fe1f64c3ad52388bfa8434ac73 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "common_audio/include/audio_util.h"
25#include "common_audio/resampler/include/push_resampler.h"
26#include "common_audio/resampler/push_sinc_resampler.h"
27#include "common_audio/signal_processing/include/signal_processing_library.h"
28#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
29#include "modules/audio_processing/audio_processing_impl.h"
Sam Zackrisson0beac582017-09-25 12:04:02 +020030#include "modules/audio_processing/include/mock_audio_processing.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020031#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "modules/audio_processing/test/protobuf_utils.h"
33#include "modules/audio_processing/test/test_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/arraysize.h"
35#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "rtc_base/gtest_prod_util.h"
38#include "rtc_base/ignore_wundef.h"
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +010039#include "rtc_base/numerics/safe_conversions.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010040#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/protobuf_utils.h"
Steve Anton10542f22019-01-11 09:11:00 -080042#include "rtc_base/ref_counted_object.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
ekmeyerson60d9b332015-08-14 10:35:55 -070069// TODO(ekmeyerson): Switch to using StreamConfig and ProcessingConfig where
70// applicable.
71
mbonadei7c2c8432017-04-07 00:59:12 -070072const int32_t kChannels[] = {1, 2};
Alejandro Luebs47748742015-05-22 12:00:21 -070073const int kSampleRates[] = {8000, 16000, 32000, 48000};
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +000074
aluebseb3603b2016-04-20 15:27:58 -070075#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
76// Android doesn't support 48kHz.
77const int kProcessSampleRates[] = {8000, 16000, 32000};
78#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Alejandro Luebs47748742015-05-22 12:00:21 -070079const int kProcessSampleRates[] = {8000, 16000, 32000, 48000};
aluebseb3603b2016-04-20 15:27:58 -070080#endif
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000081
ekmeyerson60d9b332015-08-14 10:35:55 -070082enum StreamDirection { kForward = 0, kReverse };
83
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000084void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 19:08:33 +020085 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
86 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000087 cb_int.channels());
Peter Kasting69558702016-01-12 16:26:35 -080088 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +020089 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000090 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000091}
andrew@webrtc.org17e40642014-03-04 20:58:13 +000092
Per Åhgren2507f8c2020-03-19 12:33:29 +010093void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
94 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000095}
96
Jonas Olssona4d87372019-07-05 19:08:33 +020097void MixStereoToMono(const float* stereo,
98 float* mono,
pkasting25702cb2016-01-08 13:50:27 -080099 size_t samples_per_channel) {
100 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000101 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000102}
103
Jonas Olssona4d87372019-07-05 19:08:33 +0200104void MixStereoToMono(const int16_t* stereo,
105 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -0800106 size_t samples_per_channel) {
107 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000108 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
109}
110
pkasting25702cb2016-01-08 13:50:27 -0800111void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
112 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000113 stereo[i * 2 + 1] = stereo[i * 2];
114 }
115}
116
yujo36b1a5f2017-06-12 12:45:32 -0700117void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800118 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000119 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
120 }
121}
122
Per Åhgren2507f8c2020-03-19 12:33:29 +0100123void SetFrameTo(Int16FrameData* frame, int16_t value) {
124 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700125 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100126 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 }
128}
129
Per Åhgren2507f8c2020-03-19 12:33:29 +0100130void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
131 ASSERT_EQ(2u, frame->num_channels);
132 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
133 frame->data[i] = left;
134 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000135 }
136}
137
Per Åhgren2507f8c2020-03-19 12:33:29 +0100138void ScaleFrame(Int16FrameData* frame, float scale) {
139 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700140 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100141 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000142 }
143}
144
Per Åhgren2507f8c2020-03-19 12:33:29 +0100145bool FrameDataAreEqual(const Int16FrameData& frame1,
146 const Int16FrameData& frame2) {
147 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000148 return false;
149 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100150 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000151 return false;
152 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100153 if (memcmp(
154 frame1.data.data(), frame2.data.data(),
155 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000156 return false;
157 }
158 return true;
159}
160
Per Åhgren2507f8c2020-03-19 12:33:29 +0100161rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
162 int16_t* ptr = frame->data.data();
163 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200164 return rtc::ArrayView<int16_t>(ptr, len);
165}
166
Per Åhgren2507f8c2020-03-19 12:33:29 +0100167rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
168 const int16_t* ptr = frame.data.data();
169 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200170 return rtc::ArrayView<const int16_t>(ptr, len);
171}
172
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000173void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200174 AudioProcessing::Config apm_config = ap->GetConfig();
175 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000176#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200177 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100178
179 apm_config.gain_controller1.enabled = true;
180 apm_config.gain_controller1.mode =
181 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000182#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200183 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000184
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100185 apm_config.gain_controller1.enabled = true;
186 apm_config.gain_controller1.mode =
187 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000188#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000189
saza0bad15f2019-10-16 11:46:11 +0200190 apm_config.noise_suppression.enabled = true;
191
peah8271d042016-11-22 07:24:52 -0800192 apm_config.high_pass_filter.enabled = true;
Henrik Boström09aaf6f2022-02-14 12:02:45 +0000193 apm_config.voice_detection.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100194 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800195 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000196}
197
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000198// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000199template <class T>
200T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200201 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000202}
203
Per Åhgren2507f8c2020-03-19 12:33:29 +0100204int16_t MaxAudioFrame(const Int16FrameData& frame) {
205 const size_t length = frame.samples_per_channel * frame.num_channels;
206 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800207 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100208 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000209 }
210
211 return max_data;
212}
213
Alex Loiko890988c2017-08-31 10:25:48 +0200214void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700215 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000216 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000217 ASSERT_TRUE(file != NULL);
218
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100219 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000220 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800221 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000222 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000223
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000224 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000225 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200226 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000227 fclose(file);
228}
229
Alex Loiko890988c2017-08-31 10:25:48 +0200230std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200231 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000232 // Resource files are all stereo.
233 ss << name << sample_rate_hz / 1000 << "_stereo";
234 return test::ResourcePath(ss.str(), "pcm");
235}
236
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000237// Temporary filenames unique to this process. Used to be able to run these
238// tests in parallel as each process needs to be running in isolation they can't
239// have competing filenames.
240std::map<std::string, std::string> temp_filenames;
241
Alex Loiko890988c2017-08-31 10:25:48 +0200242std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000243 int input_rate,
244 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700245 int reverse_input_rate,
246 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800247 size_t num_input_channels,
248 size_t num_output_channels,
249 size_t num_reverse_input_channels,
250 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700251 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200252 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700253 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
254 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000255 if (num_output_channels == 1) {
256 ss << "mono";
257 } else if (num_output_channels == 2) {
258 ss << "stereo";
259 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100260 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000261 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700262 ss << output_rate / 1000;
263 if (num_reverse_output_channels == 1) {
264 ss << "_rmono";
265 } else if (num_reverse_output_channels == 2) {
266 ss << "_rstereo";
267 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100268 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700269 }
270 ss << reverse_output_rate / 1000;
271 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000272
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000273 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700274 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000275 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
276 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000277}
278
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000279void ClearTempFiles() {
280 for (auto& kv : temp_filenames)
281 remove(kv.second.c_str());
282}
283
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200284// Only remove "out" files. Keep "ref" files.
285void ClearTempOutFiles() {
286 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
287 const std::string& filename = it->first;
288 if (filename.substr(0, 3).compare("out") == 0) {
289 remove(it->second.c_str());
290 temp_filenames.erase(it++);
291 } else {
292 it++;
293 }
294 }
295}
296
Alex Loiko890988c2017-08-31 10:25:48 +0200297void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000298 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000299 ASSERT_TRUE(file != NULL);
300 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000301 fclose(file);
302}
303
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000304// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
305// stereo) file, converts to deinterleaved float (optionally downmixing) and
Artem Titov0b489302021-07-28 20:50:03 +0200306// returns the result in `cb`. Returns false if the file ended (or on error) and
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000307// true otherwise.
308//
Artem Titov0b489302021-07-28 20:50:03 +0200309// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000310// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200311bool ReadChunk(FILE* file,
312 int16_t* int_data,
313 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000314 ChannelBuffer<float>* cb) {
315 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000316 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000317 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
318 if (read_count != frame_size) {
319 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700320 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000321 return false; // This is expected.
322 }
323
324 S16ToFloat(int_data, frame_size, float_data);
325 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000326 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000327 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200328 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000329 }
330
331 return true;
332}
333
Per Åhgrena43178c2020-09-25 12:02:32 +0200334// Returns the reference file name that matches the current CPU
335// architecture/optimizations.
336std::string GetReferenceFilename() {
337#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
338 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
339#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
340 if (GetCPUInfo(kAVX2) != 0) {
341 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
342 }
343 return test::ResourcePath("audio_processing/output_data_float", "pb");
344#endif
345}
346
niklase@google.com470e71d2011-07-07 08:21:25 +0000347class ApmTest : public ::testing::Test {
348 protected:
349 ApmTest();
350 virtual void SetUp();
351 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000352
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200353 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000354
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200355 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000356
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000357 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200358 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000359
360 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000361 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000362 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800363 size_t num_input_channels,
364 size_t num_output_channels,
365 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000366 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000367 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000368 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100369 bool ReadFrame(FILE* file, Int16FrameData* frame);
370 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
371 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200372 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100373 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000374 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200375 void ProcessDelayVerificationTest(int delay_ms,
376 int system_delay_ms,
377 int delay_min,
378 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700379 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800380 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700381 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800382 void TestChangingForwardChannels(size_t num_in_channels,
383 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700384 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800385 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700386 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000387 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
388 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000389 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000390 int ProcessStreamChooser(Format format);
391 int AnalyzeReverseStreamChooser(Format format);
392 void ProcessDebugDump(const std::string& in_filename,
393 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800394 Format format,
395 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000396 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000397
398 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000399 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200400 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100401 Int16FrameData frame_;
402 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 15:40:04 +0100403 std::unique_ptr<ChannelBuffer<float>> float_cb_;
404 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000405 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800406 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000407 FILE* far_file_;
408 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000409 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000410};
411
412ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000413 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200414 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000415 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000416 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000417 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000418 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000419 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200420 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100421 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100422 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100423 apm_config.pipeline.maximum_internal_processing_rate = 48000;
424 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000425}
niklase@google.com470e71d2011-07-07 08:21:25 +0000426
427void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000428 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000429
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000430 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000431}
432
433void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000434 if (far_file_) {
435 ASSERT_EQ(0, fclose(far_file_));
436 }
437 far_file_ = NULL;
438
439 if (near_file_) {
440 ASSERT_EQ(0, fclose(near_file_));
441 }
442 near_file_ = NULL;
443
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000444 if (out_file_) {
445 ASSERT_EQ(0, fclose(out_file_));
446 }
447 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000448}
449
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000450void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200451 ASSERT_EQ(
452 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100453 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200454 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100455 {revframe_.sample_rate_hz, revframe_.num_channels},
456 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000457}
458
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000459void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000460 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000461 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800462 size_t num_input_channels,
463 size_t num_output_channels,
464 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000465 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200466 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000467 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000468 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000469
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200470 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000471 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000472 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000473
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000474 if (far_file_) {
475 ASSERT_EQ(0, fclose(far_file_));
476 }
477 std::string filename = ResourceFilePath("far", sample_rate_hz);
478 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200479 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000480
481 if (near_file_) {
482 ASSERT_EQ(0, fclose(near_file_));
483 }
484 filename = ResourceFilePath("near", sample_rate_hz);
485 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200486 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000487
488 if (open_output_file) {
489 if (out_file_) {
490 ASSERT_EQ(0, fclose(out_file_));
491 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700492 filename = OutputFilePath(
493 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
494 reverse_sample_rate_hz, num_input_channels, num_output_channels,
495 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000496 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200497 ASSERT_TRUE(out_file_ != NULL)
498 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000499 }
500}
501
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000502void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000503 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000504}
505
Jonas Olssona4d87372019-07-05 19:08:33 +0200506bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100507 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000508 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000509 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100510 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200511 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100512 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000513 if (read_count != frame_size) {
514 // Check that the file really ended.
515 EXPECT_NE(0, feof(file));
516 return false; // This is expected.
517 }
518
Per Åhgren2507f8c2020-03-19 12:33:29 +0100519 if (frame->num_channels == 1) {
520 MixStereoToMono(frame->data.data(), frame->data.data(),
521 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000522 }
523
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000524 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000525 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000526 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000527 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000528}
529
Per Åhgren2507f8c2020-03-19 12:33:29 +0100530bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000531 return ReadFrame(file, frame, NULL);
532}
533
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000534// If the end of the file has been reached, rewind it and attempt to read the
535// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200536void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100537 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000538 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200539 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000540 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200541 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000542 }
543}
544
Per Åhgren2507f8c2020-03-19 12:33:29 +0100545void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000546 ReadFrameWithRewind(file, frame, NULL);
547}
548
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000549int ApmTest::ProcessStreamChooser(Format format) {
550 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100551 return apm_->ProcessStream(
552 frame_.data.data(),
553 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
554 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100555 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000556 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200557 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100558 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100559 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100560 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200561 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000562}
563
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000564int ApmTest::AnalyzeReverseStreamChooser(Format format) {
565 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100566 return apm_->ProcessReverseStream(
567 revframe_.data.data(),
568 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
569 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
570 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000571 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000572 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100573 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100574 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000575}
576
Jonas Olssona4d87372019-07-05 19:08:33 +0200577void ApmTest::ProcessDelayVerificationTest(int delay_ms,
578 int system_delay_ms,
579 int delay_min,
580 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200581 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000582 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100583 Int16FrameData tmp_frame;
584 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000585 bool causal = true;
586
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200587 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000588 SetFrameTo(&tmp_frame, 0);
589
590 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200591 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000592 int frame_delay = delay_ms / 10;
593 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100594 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000595 frame->CopyFrom(tmp_frame);
596 frame_queue.push(frame);
597 frame_delay++;
598 causal = false;
599 }
600 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100601 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000602 frame->CopyFrom(tmp_frame);
603 frame_queue.push(frame);
604 frame_delay--;
605 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000606 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
607 // need enough frames with audio to have reliable estimates, but as few as
608 // possible to keep processing time down. 4.5 seconds seemed to be a good
609 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000610 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100611 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000612 frame->CopyFrom(tmp_frame);
613 // Use the near end recording, since that has more speech in it.
614 ASSERT_TRUE(ReadFrame(near_file_, frame));
615 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100616 Int16FrameData* reverse_frame = frame;
617 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000618 if (!causal) {
619 reverse_frame = frame_queue.front();
620 // When we call ProcessStream() the frame is modified, so we can't use the
621 // pointer directly when things are non-causal. Use an intermediate frame
622 // and copy the data.
623 process_frame = &tmp_frame;
624 process_frame->CopyFrom(*frame);
625 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100626 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
627 reverse_frame->data.data(),
628 StreamConfig(reverse_frame->sample_rate_hz,
629 reverse_frame->num_channels),
630 StreamConfig(reverse_frame->sample_rate_hz,
631 reverse_frame->num_channels),
632 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000633 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100634 EXPECT_EQ(apm_->kNoError,
635 apm_->ProcessStream(process_frame->data.data(),
636 StreamConfig(process_frame->sample_rate_hz,
637 process_frame->num_channels),
638 StreamConfig(process_frame->sample_rate_hz,
639 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100640 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000641 frame = frame_queue.front();
642 frame_queue.pop();
643 delete frame;
644
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000645 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000646 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100647 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000648 }
649 }
650
651 rewind(near_file_);
652 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100653 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000654 frame_queue.pop();
655 delete frame;
656 }
657 // Calculate expected delay estimate and acceptable regions. Further,
658 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700659 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100660 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700661 const int expected_median =
662 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
663 const int expected_median_high = rtc::SafeClamp<int>(
664 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700665 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700666 const int expected_median_low = rtc::SafeClamp<int>(
667 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700668 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000669 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100670 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200671 ASSERT_TRUE(stats.delay_median_ms.has_value());
672 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000673 EXPECT_GE(expected_median_high, median);
674 EXPECT_LE(expected_median_low, median);
675}
676
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000677void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000679 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000680
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000681 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200682 AudioProcessing::Config apm_config = apm_->GetConfig();
683 apm_config.gain_controller1.enabled = true;
684 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200685 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000686
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000687 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200688 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000689 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200690 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000691
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000692 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200693 apm_config.echo_canceller.enabled = true;
694 apm_config.echo_canceller.mobile_mode = false;
695 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000696 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200697 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200698 apm_config.gain_controller1.enabled = false;
699 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000700
701 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000702 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100703 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000704
705 // Resets after successful ProcessStream().
706 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000707 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100708 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000709
710 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200711 apm_config.gain_controller1.enabled = true;
712 apm_->ApplyConfig(apm_config);
713 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100714 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200715 apm_config.gain_controller1.enabled = false;
716 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000717
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000718 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200719 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100720 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000721
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000722 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000723 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200724 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000725 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000726}
727
728TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000729 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000730}
731
732TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000733 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000734}
735
Michael Graczyk86c6d332015-07-23 11:41:39 -0700736void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800737 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700738 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100739 frame_.num_channels = num_channels;
740
741 EXPECT_EQ(expected_return,
742 apm_->ProcessStream(
743 frame_.data.data(),
744 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
745 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100746 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100747 EXPECT_EQ(expected_return,
748 apm_->ProcessReverseStream(
749 frame_.data.data(),
750 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
751 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
752 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000753}
754
Michael Graczyk86c6d332015-07-23 11:41:39 -0700755void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800756 size_t num_in_channels,
757 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700758 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100759 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700760 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
761
762 EXPECT_EQ(expected_return,
763 apm_->ProcessStream(float_cb_->channels(), input_stream,
764 output_stream, float_cb_->channels()));
765}
766
767void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800768 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700769 AudioProcessing::Error expected_return) {
770 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100771 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700772 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100773 {frame_.sample_rate_hz, num_rev_channels},
774 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700775
ekmeyerson60d9b332015-08-14 10:35:55 -0700776 EXPECT_EQ(
777 expected_return,
778 apm_->ProcessReverseStream(
779 float_cb_->channels(), processing_config.reverse_input_stream(),
780 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700781}
782
783TEST_F(ApmTest, ChannelsInt16Interface) {
784 // Testing number of invalid and valid channels.
785 Init(16000, 16000, 16000, 4, 4, 4, false);
786
787 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
788
Peter Kasting69558702016-01-12 16:26:35 -0800789 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700790 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000792 }
793}
794
Michael Graczyk86c6d332015-07-23 11:41:39 -0700795TEST_F(ApmTest, Channels) {
796 // Testing number of invalid and valid channels.
797 Init(16000, 16000, 16000, 4, 4, 4, false);
798
799 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
800 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
801
Peter Kasting69558702016-01-12 16:26:35 -0800802 for (size_t i = 1; i < 4; ++i) {
803 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700804 // Output channels much be one or match input channels.
805 if (j == 1 || i == j) {
806 TestChangingForwardChannels(i, j, kNoErr);
807 TestChangingReverseChannels(i, kNoErr);
808
809 EXPECT_EQ(i, apm_->num_input_channels());
810 EXPECT_EQ(j, apm_->num_output_channels());
811 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800812 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700813 } else {
814 TestChangingForwardChannels(i, j,
815 AudioProcessing::kBadNumberChannelsError);
816 }
817 }
818 }
819}
820
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000821TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100822 // Testing some valid sample rates.
823 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
824 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000825 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000826 }
827}
828
Sam Zackrissone277bde2019-10-25 10:07:54 +0200829// This test repeatedly reconfigures the pre-amplifier in APM, processes a
830// number of frames, and checks that output signal has the right level.
831TEST_F(ApmTest, PreAmplifier) {
832 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200833 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100834 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200835 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100836 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200837 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
838 }
839 }
840 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100841 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200842 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200843
Per Åhgren2507f8c2020-03-19 12:33:29 +0100844 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200845 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
846 return std::accumulate(data.begin(), data.end(), 0.0f,
847 [](float a, float b) { return a + b * b; }) /
848 data.size() / 32768 / 32768;
849 };
850
851 const float input_power = compute_power(tmp_frame);
852 // Double-check that the input data is large compared to the error kEpsilon.
853 constexpr float kEpsilon = 1e-4f;
854 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
855
856 // 1. Enable pre-amp with 0 dB gain.
857 AudioProcessing::Config config = apm_->GetConfig();
858 config.pre_amplifier.enabled = true;
859 config.pre_amplifier.fixed_gain_factor = 1.0f;
860 apm_->ApplyConfig(config);
861
862 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200863 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200864 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
865 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200866 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200867 EXPECT_NEAR(output_power, input_power, kEpsilon);
868 config = apm_->GetConfig();
869 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
870
871 // 2. Change pre-amp gain via ApplyConfig.
872 config.pre_amplifier.fixed_gain_factor = 2.0f;
873 apm_->ApplyConfig(config);
874
875 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200876 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200877 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
878 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200879 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200880 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
881 config = apm_->GetConfig();
882 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
883
884 // 3. Change pre-amp gain via a RuntimeSetting.
885 apm_->SetRuntimeSetting(
886 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
887
888 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200889 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200890 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
891 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200892 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200893 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
894 config = apm_->GetConfig();
895 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
896}
897
Per Åhgrendb5d7282021-03-15 16:31:04 +0000898// This test a simple test that ensures that the emulated analog mic gain
899// functionality runs without crashing.
900TEST_F(ApmTest, AnalogMicGainEmulation) {
901 // Fill the audio frame with a sawtooth pattern.
902 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
903 const size_t samples_per_channel = frame_.samples_per_channel;
904 for (size_t i = 0; i < samples_per_channel; i++) {
905 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
906 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
907 }
908 }
909 // Cache the frame in tmp_frame.
910 Int16FrameData tmp_frame;
911 tmp_frame.CopyFrom(frame_);
912
913 // Enable the analog gain emulation.
914 AudioProcessing::Config config = apm_->GetConfig();
915 config.capture_level_adjustment.enabled = true;
916 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
917 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
918 config.gain_controller1.enabled = true;
919 config.gain_controller1.mode =
920 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
921 config.gain_controller1.analog_gain_controller.enabled = true;
922 apm_->ApplyConfig(config);
923
924 // Process a number of frames to ensure that the code runs without crashes.
925 for (int i = 0; i < 20; ++i) {
926 frame_.CopyFrom(tmp_frame);
927 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
928 }
929}
930
931// This test repeatedly reconfigures the capture level adjustment functionality
932// in APM, processes a number of frames, and checks that output signal has the
933// right level.
934TEST_F(ApmTest, CaptureLevelAdjustment) {
935 // Fill the audio frame with a sawtooth pattern.
936 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
937 const size_t samples_per_channel = frame_.samples_per_channel;
938 for (size_t i = 0; i < samples_per_channel; i++) {
939 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
940 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
941 }
942 }
943 // Cache the frame in tmp_frame.
944 Int16FrameData tmp_frame;
945 tmp_frame.CopyFrom(frame_);
946
947 auto compute_power = [](const Int16FrameData& frame) {
948 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
949 return std::accumulate(data.begin(), data.end(), 0.0f,
950 [](float a, float b) { return a + b * b; }) /
951 data.size() / 32768 / 32768;
952 };
953
954 const float input_power = compute_power(tmp_frame);
955 // Double-check that the input data is large compared to the error kEpsilon.
956 constexpr float kEpsilon = 1e-20f;
957 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
958
959 // 1. Enable pre-amp with 0 dB gain.
960 AudioProcessing::Config config = apm_->GetConfig();
961 config.capture_level_adjustment.enabled = true;
962 config.capture_level_adjustment.pre_gain_factor = 0.5f;
963 config.capture_level_adjustment.post_gain_factor = 4.f;
964 const float expected_output_power1 =
965 config.capture_level_adjustment.pre_gain_factor *
966 config.capture_level_adjustment.pre_gain_factor *
967 config.capture_level_adjustment.post_gain_factor *
968 config.capture_level_adjustment.post_gain_factor * input_power;
969 apm_->ApplyConfig(config);
970
971 for (int i = 0; i < 20; ++i) {
972 frame_.CopyFrom(tmp_frame);
973 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
974 }
975 float output_power = compute_power(frame_);
976 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
977 config = apm_->GetConfig();
978 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
979 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
980
981 // 2. Change pre-amp gain via ApplyConfig.
982 config.capture_level_adjustment.pre_gain_factor = 1.0f;
983 config.capture_level_adjustment.post_gain_factor = 2.f;
984 const float expected_output_power2 =
985 config.capture_level_adjustment.pre_gain_factor *
986 config.capture_level_adjustment.pre_gain_factor *
987 config.capture_level_adjustment.post_gain_factor *
988 config.capture_level_adjustment.post_gain_factor * input_power;
989 apm_->ApplyConfig(config);
990
991 for (int i = 0; i < 20; ++i) {
992 frame_.CopyFrom(tmp_frame);
993 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
994 }
995 output_power = compute_power(frame_);
996 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
997 config = apm_->GetConfig();
998 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
999 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1000
1001 // 3. Change pre-amp gain via a RuntimeSetting.
1002 constexpr float kPreGain3 = 0.5f;
1003 constexpr float kPostGain3 = 3.f;
1004 const float expected_output_power3 =
1005 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1006
1007 apm_->SetRuntimeSetting(
1008 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1009 apm_->SetRuntimeSetting(
1010 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1011
1012 for (int i = 0; i < 20; ++i) {
1013 frame_.CopyFrom(tmp_frame);
1014 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1015 }
1016 output_power = compute_power(frame_);
1017 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1018 config = apm_->GetConfig();
1019 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1020 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1021}
1022
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001023TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001024 AudioProcessing::Config config = apm_->GetConfig();
1025 config.gain_controller1.enabled = false;
1026 apm_->ApplyConfig(config);
1027 config.gain_controller1.enabled = true;
1028 apm_->ApplyConfig(config);
1029
niklase@google.com470e71d2011-07-07 08:21:25 +00001030 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001031 for (auto mode :
1032 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1033 AudioProcessing::Config::GainController1::kFixedDigital,
1034 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1035 config.gain_controller1.mode = mode;
1036 apm_->ApplyConfig(config);
1037 apm_->set_stream_analog_level(100);
1038 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001039 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001040
Sam Zackrisson41478c72019-10-15 10:10:26 +02001041 // Testing target levels
1042 for (int target_level_dbfs : {0, 15, 31}) {
1043 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1044 apm_->ApplyConfig(config);
1045 apm_->set_stream_analog_level(100);
1046 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 }
1048
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001049 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001050 for (int compression_gain_db : {0, 10, 90}) {
1051 config.gain_controller1.compression_gain_db = compression_gain_db;
1052 apm_->ApplyConfig(config);
1053 apm_->set_stream_analog_level(100);
1054 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001055 }
1056
1057 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001058 for (bool enable : {false, true}) {
1059 config.gain_controller1.enable_limiter = enable;
1060 apm_->ApplyConfig(config);
1061 apm_->set_stream_analog_level(100);
1062 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1063 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001064
Hanna Silencd597042021-11-02 11:02:48 +01001065 // Testing level limits.
1066 constexpr int kMinLevel = 0;
1067 constexpr int kMaxLevel = 255;
1068 apm_->set_stream_analog_level(kMinLevel);
1069 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1070 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1071 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1072 apm_->set_stream_analog_level(kMaxLevel);
1073 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001074}
1075
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001076#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001077using ApmDeathTest = ApmTest;
1078
1079TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001080 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001081 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001082 config.gain_controller1.target_level_dbfs = -1;
1083 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001084}
1085
Tommia5e07cc2020-05-26 21:40:37 +02001086TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001087 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001088 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001089 config.gain_controller1.target_level_dbfs = 32;
1090 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001091}
1092
Tommia5e07cc2020-05-26 21:40:37 +02001093TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001094 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001095 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001096 config.gain_controller1.compression_gain_db = -1;
1097 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001098}
1099
Tommia5e07cc2020-05-26 21:40:37 +02001100TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001101 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001102 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001103 config.gain_controller1.compression_gain_db = 91;
1104 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001105}
1106
Tommia5e07cc2020-05-26 21:40:37 +02001107TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001108 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001109 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001110 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001111 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001112}
1113
Tommia5e07cc2020-05-26 21:40:37 +02001114TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001115 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001116 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001117 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001118 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001119}
1120#endif
1121
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001122void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001123 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001124 auto config = apm_->GetConfig();
1125 config.gain_controller1.enabled = true;
1126 config.gain_controller1.mode =
1127 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1128 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001129
1130 int out_analog_level = 0;
1131 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001132 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001133 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001134 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001135
1136 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001137 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001138 EXPECT_EQ(apm_->kNoError,
1139 apm_->ProcessStream(
1140 frame_.data.data(),
1141 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1142 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001143 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001144 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001145 }
1146
1147 // Ensure the AGC is still able to reach the maximum.
1148 EXPECT_EQ(255, out_analog_level);
1149}
1150
1151// Verifies that despite volume slider quantization, the AGC can continue to
1152// increase its volume.
1153TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001154 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001155 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1156 }
1157}
1158
1159void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001160 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001161 auto config = apm_->GetConfig();
1162 config.gain_controller1.enabled = true;
1163 config.gain_controller1.mode =
1164 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1165 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001166
1167 int out_analog_level = 100;
1168 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001169 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001170 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001171 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001172
Sam Zackrisson41478c72019-10-15 10:10:26 +02001173 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001174 EXPECT_EQ(apm_->kNoError,
1175 apm_->ProcessStream(
1176 frame_.data.data(),
1177 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1178 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001179 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001180 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001181 }
1182
1183 // Ensure the volume was raised.
1184 EXPECT_GT(out_analog_level, 100);
1185 int highest_level_reached = out_analog_level;
1186 // Simulate a user manual volume change.
1187 out_analog_level = 100;
1188
1189 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001190 ReadFrameWithRewind(near_file_, &frame_);
1191 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001192
Sam Zackrisson41478c72019-10-15 10:10:26 +02001193 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001194 EXPECT_EQ(apm_->kNoError,
1195 apm_->ProcessStream(
1196 frame_.data.data(),
1197 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1198 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001199 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001200 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001201 // Check that AGC respected the manually adjusted volume.
1202 EXPECT_LT(out_analog_level, highest_level_reached);
1203 }
1204 // Check that the volume was still raised.
1205 EXPECT_GT(out_analog_level, 100);
1206}
1207
1208TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001209 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001210 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1211 }
1212}
1213
niklase@google.com470e71d2011-07-07 08:21:25 +00001214TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001215 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001216 AudioProcessing::Config apm_config;
1217 apm_config.high_pass_filter.enabled = true;
1218 apm_->ApplyConfig(apm_config);
1219 apm_config.high_pass_filter.enabled = false;
1220 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001221}
1222
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001223TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001224 AudioProcessing::Config config = apm_->GetConfig();
1225 EXPECT_FALSE(config.echo_canceller.enabled);
1226 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001227 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001228 EXPECT_FALSE(config.noise_suppression.enabled);
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001229 EXPECT_FALSE(config.voice_detection.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001230}
1231
1232TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001233 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001234 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001235 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001236 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001237 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001238 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001239 EXPECT_EQ(apm_->kNoError,
1240 apm_->ProcessStream(
1241 frame_.data.data(),
1242 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1243 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001244 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001245 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001246 EXPECT_EQ(apm_->kNoError,
1247 apm_->ProcessReverseStream(
1248 frame_.data.data(),
1249 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1250 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1251 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001252 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001253 }
1254 }
1255}
1256
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001257TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1258 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001259 const size_t kSamples = 160;
1260 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001261 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001262 float dest[kSamples] = {};
1263
1264 auto src_channels = &src[0];
1265 auto dest_channels = &dest[0];
1266
Niels Möller4f776ac2021-07-02 11:30:54 +02001267 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001268 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1269 StreamConfig(sample_rate, 1),
1270 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001271
1272 for (size_t i = 0; i < kSamples; ++i) {
1273 EXPECT_EQ(src[i], dest[i]);
1274 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001275
1276 // Same for ProcessReverseStream.
1277 float rev_dest[kSamples] = {};
1278 auto rev_dest_channels = &rev_dest[0];
1279
1280 StreamConfig input_stream = {sample_rate, 1};
1281 StreamConfig output_stream = {sample_rate, 1};
1282 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1283 output_stream, &rev_dest_channels));
1284
1285 for (size_t i = 0; i < kSamples; ++i) {
1286 EXPECT_EQ(src[i], rev_dest[i]);
1287 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001288}
1289
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001290TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1291 EnableAllComponents();
1292
pkasting25702cb2016-01-08 13:50:27 -08001293 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001294 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1295 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001296 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001297 ASSERT_EQ(0, feof(far_file_));
1298 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001299 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001300 CopyLeftToRightChannel(revframe_.data.data(),
1301 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001302
Per Åhgren2507f8c2020-03-19 12:33:29 +01001303 ASSERT_EQ(
1304 kNoErr,
1305 apm_->ProcessReverseStream(
1306 revframe_.data.data(),
1307 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1308 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1309 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001310
Per Åhgren2507f8c2020-03-19 12:33:29 +01001311 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001312
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001313 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001314 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001315 ASSERT_EQ(kNoErr,
1316 apm_->ProcessStream(
1317 frame_.data.data(),
1318 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1319 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001320 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001321 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001322
Per Åhgren2507f8c2020-03-19 12:33:29 +01001323 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001324 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001325 rewind(far_file_);
1326 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001327 }
1328}
1329
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001330TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001331 // Verify the filter is not active through undistorted audio when:
1332 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001333 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001334 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001335 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001336 EXPECT_EQ(apm_->kNoError,
1337 apm_->ProcessStream(
1338 frame_.data.data(),
1339 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1340 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001341 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001342 EXPECT_EQ(apm_->kNoError,
1343 apm_->ProcessStream(
1344 frame_.data.data(),
1345 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1346 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001347 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001348 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001349
1350 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001351 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001352 SetFrameTo(&frame_, 1000);
1353 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001354 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001355 EXPECT_EQ(apm_->kNoError,
1356 apm_->ProcessStream(
1357 frame_.data.data(),
1358 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1359 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001360 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001361 EXPECT_EQ(apm_->kNoError,
1362 apm_->ProcessStream(
1363 frame_.data.data(),
1364 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1365 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001366 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001367 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001368 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001369
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001370 // 3. Only GetStatistics-reporting VAD is enabled...
1371 SetFrameTo(&frame_, 1000);
1372 frame_copy.CopyFrom(frame_);
1373 apm_config.voice_detection.enabled = true;
1374 apm_->ApplyConfig(apm_config);
1375 EXPECT_EQ(apm_->kNoError,
1376 apm_->ProcessStream(
1377 frame_.data.data(),
1378 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1379 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1380 frame_.data.data()));
1381 EXPECT_EQ(apm_->kNoError,
1382 apm_->ProcessStream(
1383 frame_.data.data(),
1384 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1385 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1386 frame_.data.data()));
1387 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1388 apm_config.voice_detection.enabled = false;
1389 apm_->ApplyConfig(apm_config);
1390
1391 // 4. The VAD is enabled...
1392 SetFrameTo(&frame_, 1000);
1393 frame_copy.CopyFrom(frame_);
1394 apm_config.voice_detection.enabled = true;
1395 apm_->ApplyConfig(apm_config);
1396 EXPECT_EQ(apm_->kNoError,
1397 apm_->ProcessStream(
1398 frame_.data.data(),
1399 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1400 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1401 frame_.data.data()));
1402 EXPECT_EQ(apm_->kNoError,
1403 apm_->ProcessStream(
1404 frame_.data.data(),
1405 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1406 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1407 frame_.data.data()));
1408 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
1409 apm_config.voice_detection.enabled = false;
1410 apm_->ApplyConfig(apm_config);
1411
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001412 // Check the test is valid. We should have distortion from the filter
1413 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001414 apm_config.echo_canceller.enabled = true;
1415 apm_config.echo_canceller.mobile_mode = false;
1416 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001417 frame_.samples_per_channel = 320;
1418 frame_.num_channels = 2;
1419 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001420 SetFrameTo(&frame_, 1000);
1421 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001422 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001423 EXPECT_EQ(apm_->kNoError,
1424 apm_->ProcessStream(
1425 frame_.data.data(),
1426 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1427 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001428 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001429 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001430}
1431
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001432#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1433void ApmTest::ProcessDebugDump(const std::string& in_filename,
1434 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001435 Format format,
1436 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001437 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001438 FILE* in_file = fopen(in_filename.c_str(), "rb");
1439 ASSERT_TRUE(in_file != NULL);
1440 audioproc::Event event_msg;
1441 bool first_init = true;
1442
1443 while (ReadMessageFromFile(in_file, &event_msg)) {
1444 if (event_msg.type() == audioproc::Event::INIT) {
1445 const audioproc::Init msg = event_msg.init();
1446 int reverse_sample_rate = msg.sample_rate();
1447 if (msg.has_reverse_sample_rate()) {
1448 reverse_sample_rate = msg.reverse_sample_rate();
1449 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001450 int output_sample_rate = msg.sample_rate();
1451 if (msg.has_output_sample_rate()) {
1452 output_sample_rate = msg.output_sample_rate();
1453 }
1454
Jonas Olssona4d87372019-07-05 19:08:33 +02001455 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1456 msg.num_input_channels(), msg.num_output_channels(),
1457 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001458 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001459 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001460 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001461 auto aec_dump =
1462 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1463 EXPECT_TRUE(aec_dump);
1464 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001465 first_init = false;
1466 }
1467
1468 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1469 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1470
1471 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001472 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001473 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001474 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001475 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1476 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001477 }
1478 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001479 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001480 if (format == kFloatFormat) {
1481 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001482 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001483 }
1484 }
1485 AnalyzeReverseStreamChooser(format);
1486
1487 } else if (event_msg.type() == audioproc::Event::STREAM) {
1488 const audioproc::Stream msg = event_msg.stream();
1489 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001490 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001491
Sam Zackrisson41478c72019-10-15 10:10:26 +02001492 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001493 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001494 if (msg.has_keypress()) {
1495 apm_->set_stream_key_pressed(msg.keypress());
1496 } else {
1497 apm_->set_stream_key_pressed(true);
1498 }
1499
1500 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001501 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001502 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001503 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001504 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1505 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001506 }
1507 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001508 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001509 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001510 if (format == kFloatFormat) {
1511 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001512 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001513 }
1514 }
1515 ProcessStreamChooser(format);
1516 }
1517 }
aleloif4dd1912017-06-15 01:55:38 -07001518 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001519 fclose(in_file);
1520}
1521
1522void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001523 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001524 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001525 std::string format_string;
1526 switch (format) {
1527 case kIntFormat:
1528 format_string = "_int";
1529 break;
1530 case kFloatFormat:
1531 format_string = "_float";
1532 break;
1533 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001534 const std::string ref_filename = test::TempFilename(
1535 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1536 const std::string out_filename = test::TempFilename(
1537 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001538 const std::string limited_filename = test::TempFilename(
1539 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1540 const size_t logging_limit_bytes = 100000;
1541 // We expect at least this many bytes in the created logfile.
1542 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001543 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001544 ProcessDebugDump(in_filename, ref_filename, format, -1);
1545 ProcessDebugDump(ref_filename, out_filename, format, -1);
1546 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001547
1548 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1549 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001550 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001551 ASSERT_TRUE(ref_file != NULL);
1552 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001553 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001554 std::unique_ptr<uint8_t[]> ref_bytes;
1555 std::unique_ptr<uint8_t[]> out_bytes;
1556 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001557
1558 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1559 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001560 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001561 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001562 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001563 while (ref_size > 0 && out_size > 0) {
1564 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001565 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001566 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001567 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001568 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001569 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001570 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1571 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001572 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001573 }
1574 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001575 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1576 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001577 EXPECT_NE(0, feof(ref_file));
1578 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001579 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001580 ASSERT_EQ(0, fclose(ref_file));
1581 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001582 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001583 remove(ref_filename.c_str());
1584 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001585 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001586}
1587
pbosc7a65692016-05-06 12:50:04 -07001588TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001589 VerifyDebugDumpTest(kIntFormat);
1590}
1591
pbosc7a65692016-05-06 12:50:04 -07001592TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001593 VerifyDebugDumpTest(kFloatFormat);
1594}
1595#endif
1596
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001597// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001598TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001599 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001600 const std::string filename =
1601 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001602 {
1603 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1604 EXPECT_FALSE(aec_dump);
1605 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001606
1607#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1608 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001609 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001610
aleloif4dd1912017-06-15 01:55:38 -07001611 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1612 EXPECT_TRUE(aec_dump);
1613 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001614 EXPECT_EQ(apm_->kNoError,
1615 apm_->ProcessStream(
1616 frame_.data.data(),
1617 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1618 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001619 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001620 EXPECT_EQ(apm_->kNoError,
1621 apm_->ProcessReverseStream(
1622 revframe_.data.data(),
1623 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1624 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1625 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001626 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001627
1628 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001629 FILE* fid = fopen(filename.c_str(), "r");
1630 ASSERT_TRUE(fid != NULL);
1631
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001632 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001633 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001634 ASSERT_EQ(0, remove(filename.c_str()));
1635#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001636 // Verify the file has NOT been written.
1637 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1638#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1639}
1640
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001641// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001642TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001643 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001644
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001645 const std::string filename =
1646 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001647 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1648 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001649
1650#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1651 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001652 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001653
Niels Möllere8e4dc42019-06-11 14:04:16 +02001654 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001655 EXPECT_TRUE(aec_dump);
1656 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001657 EXPECT_EQ(apm_->kNoError,
1658 apm_->ProcessReverseStream(
1659 revframe_.data.data(),
1660 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1661 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1662 revframe_.data.data()));
1663 EXPECT_EQ(apm_->kNoError,
1664 apm_->ProcessStream(
1665 frame_.data.data(),
1666 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1667 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001668 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001669 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001670
1671 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001672 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001673 ASSERT_TRUE(fid != NULL);
1674
1675 // Clean it up.
1676 ASSERT_EQ(0, fclose(fid));
1677 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001678#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1679}
1680
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001681// TODO(andrew): Add a test to process a few frames with different combinations
1682// of enabled components.
1683
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001684TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001685 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001686 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001687
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001688 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001689 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001690 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001691 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001692 for (size_t i = 0; i < arraysize(kChannels); i++) {
1693 for (size_t j = 0; j < arraysize(kChannels); j++) {
1694 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001695 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001696 test->set_num_reverse_channels(kChannels[i]);
1697 test->set_num_input_channels(kChannels[j]);
1698 test->set_num_output_channels(kChannels[j]);
1699 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001700 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001701 }
1702 }
1703 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001704#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1705 // To test the extended filter mode.
1706 audioproc::Test* test = ref_data.add_test();
1707 test->set_num_reverse_channels(2);
1708 test->set_num_input_channels(2);
1709 test->set_num_output_channels(2);
1710 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1711 test->set_use_aec_extended_filter(true);
1712#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001713 }
1714
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001715 for (int i = 0; i < ref_data.test_size(); i++) {
1716 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001717
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001718 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001719 // TODO(ajm): We no longer allow different input and output channels. Skip
1720 // these tests for now, but they should be removed from the set.
1721 if (test->num_input_channels() != test->num_output_channels())
1722 continue;
1723
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01001724 apm_ = AudioProcessingBuilderForTesting()
1725 .SetEchoDetector(CreateEchoDetector())
1726 .Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001727 AudioProcessing::Config apm_config = apm_->GetConfig();
1728 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1729 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001730
1731 EnableAllComponents();
1732
Jonas Olssona4d87372019-07-05 19:08:33 +02001733 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001734 static_cast<size_t>(test->num_input_channels()),
1735 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001736 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001737
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001738 int frame_count = 0;
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001739 int has_voice_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001740 int analog_level = 127;
1741 int analog_level_average = 0;
1742 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001743#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001744 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001745#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001746
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001747 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001748 EXPECT_EQ(
1749 apm_->kNoError,
1750 apm_->ProcessReverseStream(
1751 revframe_.data.data(),
1752 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1753 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1754 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001755
1756 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001757 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001758
Per Åhgren2507f8c2020-03-19 12:33:29 +01001759 EXPECT_EQ(apm_->kNoError,
1760 apm_->ProcessStream(
1761 frame_.data.data(),
1762 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1763 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001764 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001765
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001766 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001767 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001768 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001769
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001770 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001771
Sam Zackrisson41478c72019-10-15 10:10:26 +02001772 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001773 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001774 AudioProcessingStats stats = apm_->GetStatistics();
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001775 EXPECT_TRUE(stats.voice_detected);
1776 has_voice_count += *stats.voice_detected ? 1 : 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001777
Per Åhgren2507f8c2020-03-19 12:33:29 +01001778 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001779 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001780 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001781 ASSERT_EQ(frame_size, write_count);
1782
1783 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001784 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001785 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001786
1787#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1788 const int kStatsAggregationFrameNum = 100; // 1 second.
1789 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001790 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001791 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001792
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001793 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001794 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001795 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001796 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001797 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001798 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001799 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001800 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001801
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001802 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001803 const audioproc::Test::EchoMetrics& reference =
1804 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001805 constexpr float kEpsilon = 0.01;
1806 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1807 EXPECT_NEAR(echo_return_loss_enhancement,
1808 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001809 EXPECT_NEAR(residual_echo_likelihood,
1810 reference.residual_echo_likelihood(), kEpsilon);
1811 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1812 reference.residual_echo_likelihood_recent_max(),
1813 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001814 ++stats_index;
1815 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001816 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1817 message_echo->set_echo_return_loss(echo_return_loss);
1818 message_echo->set_echo_return_loss_enhancement(
1819 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001820 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1821 message_echo->set_residual_echo_likelihood_recent_max(
1822 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001823 }
1824 }
1825#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001826 }
1827 max_output_average /= frame_count;
1828 analog_level_average /= frame_count;
1829
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001830 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001831 const int kIntNear = 1;
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001832 // When running the test on a N7 we get a {2, 6} difference of
1833 // `has_voice_count` and `max_output_average` is up to 18 higher.
1834 // All numbers being consistently higher on N7 compare to ref_data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001835 // TODO(bjornv): If we start getting more of these offsets on Android we
1836 // should consider a different approach. Either using one slack for all,
1837 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001838#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001839 const int kHasVoiceCountOffset = 3;
1840 const int kHasVoiceCountNear = 8;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001841 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001842 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001843#else
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001844 const int kHasVoiceCountOffset = 0;
1845 const int kHasVoiceCountNear = kIntNear;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001846 const int kMaxOutputAverageOffset = 0;
1847 const int kMaxOutputAverageNear = kIntNear;
1848#endif
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001849 EXPECT_NEAR(test->has_voice_count(),
1850 has_voice_count - kHasVoiceCountOffset, kHasVoiceCountNear);
1851
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001852 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001853 EXPECT_NEAR(test->max_output_average(),
1854 max_output_average - kMaxOutputAverageOffset,
1855 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001856 } else {
Henrik Boström09aaf6f2022-02-14 12:02:45 +00001857 test->set_has_voice_count(has_voice_count);
1858
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001859 test->set_analog_level_average(analog_level_average);
1860 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001861 }
1862
1863 rewind(far_file_);
1864 rewind(near_file_);
1865 }
1866
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001867 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001868 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001869 }
1870}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001871
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001872// Compares the reference and test arrays over a region around the expected
1873// delay. Finds the highest SNR in that region and adds the variance and squared
1874// error results to the supplied accumulators.
1875void UpdateBestSNR(const float* ref,
1876 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001877 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001878 int expected_delay,
1879 double* variance_acc,
1880 double* sq_error_acc) {
1881 double best_snr = std::numeric_limits<double>::min();
1882 double best_variance = 0;
1883 double best_sq_error = 0;
1884 // Search over a region of eight samples around the expected delay.
1885 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1886 ++delay) {
1887 double sq_error = 0;
1888 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001889 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001890 double error = test[i + delay] - ref[i];
1891 sq_error += error * error;
1892 variance += ref[i] * ref[i];
1893 }
1894
1895 if (sq_error == 0) {
1896 *variance_acc += variance;
1897 return;
1898 }
1899 double snr = variance / sq_error;
1900 if (snr > best_snr) {
1901 best_snr = snr;
1902 best_variance = variance;
1903 best_sq_error = sq_error;
1904 }
1905 }
1906
1907 *variance_acc += best_variance;
1908 *sq_error_acc += best_sq_error;
1909}
1910
1911// Used to test a multitude of sample rate and channel combinations. It works
1912// by first producing a set of reference files (in SetUpTestCase) that are
1913// assumed to be correct, as the used parameters are verified by other tests
1914// in this collection. Primarily the reference files are all produced at
1915// "native" rates which do not involve any resampling.
1916
1917// Each test pass produces an output file with a particular format. The output
1918// is matched against the reference file closest to its internal processing
1919// format. If necessary the output is resampled back to its process format.
1920// Due to the resampling distortion, we don't expect identical results, but
1921// enforce SNR thresholds which vary depending on the format. 0 is a special
1922// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001923typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001924class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001925 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001926 public:
1927 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001928 : input_rate_(std::get<0>(GetParam())),
1929 output_rate_(std::get<1>(GetParam())),
1930 reverse_input_rate_(std::get<2>(GetParam())),
1931 reverse_output_rate_(std::get<3>(GetParam())),
1932 expected_snr_(std::get<4>(GetParam())),
1933 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001934
1935 virtual ~AudioProcessingTest() {}
1936
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001937 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001938 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07001939 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08001940 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08001941 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
1942 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1943 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001944 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07001945 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
1946 kNativeRates[i], kNumChannels[j], kNumChannels[j],
1947 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001948 }
1949 }
1950 }
1951 }
1952
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001953 void TearDown() {
1954 // Remove "out" files after each test.
1955 ClearTempOutFiles();
1956 }
1957
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001958 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001959
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001960 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02001961 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07001962 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001963 static void ProcessFormat(int input_rate,
1964 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001965 int reverse_input_rate,
1966 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001967 size_t num_input_channels,
1968 size_t num_output_channels,
1969 size_t num_reverse_input_channels,
1970 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02001971 const std::string& output_file_prefix) {
Niels Möller4f776ac2021-07-02 11:30:54 +02001972 rtc::scoped_refptr<AudioProcessing> ap =
1973 AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001974 AudioProcessing::Config apm_config = ap->GetConfig();
1975 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1976 ap->ApplyConfig(apm_config);
1977
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001978 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001979
ekmeyerson60d9b332015-08-14 10:35:55 -07001980 ProcessingConfig processing_config = {
1981 {{input_rate, num_input_channels},
1982 {output_rate, num_output_channels},
1983 {reverse_input_rate, num_reverse_input_channels},
1984 {reverse_output_rate, num_reverse_output_channels}}};
1985 ap->Initialize(processing_config);
1986
1987 FILE* far_file =
1988 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001989 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02001990 FILE* out_file = fopen(
1991 OutputFilePath(
1992 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1993 reverse_output_rate, num_input_channels, num_output_channels,
1994 num_reverse_input_channels, num_reverse_output_channels, kForward)
1995 .c_str(),
1996 "wb");
1997 FILE* rev_out_file = fopen(
1998 OutputFilePath(
1999 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2000 reverse_output_rate, num_input_channels, num_output_channels,
2001 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2002 .c_str(),
2003 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002004 ASSERT_TRUE(far_file != NULL);
2005 ASSERT_TRUE(near_file != NULL);
2006 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002007 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002008
2009 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
2010 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002011 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
2012 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002013 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
2014 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002015 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
2016 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002017
2018 // Temporary buffers.
2019 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002020 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2021 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08002022 std::unique_ptr<float[]> float_data(new float[max_length]);
2023 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002024
2025 int analog_level = 127;
2026 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2027 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002028 EXPECT_NOERR(ap->ProcessReverseStream(
2029 rev_cb.channels(), processing_config.reverse_input_stream(),
2030 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002031
2032 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002033 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002034
2035 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002036 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2037 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002038
ekmeyerson60d9b332015-08-14 10:35:55 -07002039 // Dump forward output to file.
2040 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002041 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002042 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002043
Jonas Olssona4d87372019-07-05 19:08:33 +02002044 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2045 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002046
ekmeyerson60d9b332015-08-14 10:35:55 -07002047 // Dump reverse output to file.
2048 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2049 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002050 size_t rev_out_length =
2051 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002052
Jonas Olssona4d87372019-07-05 19:08:33 +02002053 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2054 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002055
Sam Zackrisson41478c72019-10-15 10:10:26 +02002056 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002057 }
2058 fclose(far_file);
2059 fclose(near_file);
2060 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002061 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002062 }
2063
2064 protected:
2065 int input_rate_;
2066 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002067 int reverse_input_rate_;
2068 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002069 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002070 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002071};
2072
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002073TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002074 struct ChannelFormat {
2075 int num_input;
2076 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002077 int num_reverse_input;
2078 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002079 };
2080 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002081 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2082 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002083 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002084
pkasting25702cb2016-01-08 13:50:27 -08002085 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002086 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2087 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2088 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002089
ekmeyerson60d9b332015-08-14 10:35:55 -07002090 // Verify output for both directions.
2091 std::vector<StreamDirection> stream_directions;
2092 stream_directions.push_back(kForward);
2093 stream_directions.push_back(kReverse);
2094 for (StreamDirection file_direction : stream_directions) {
2095 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2096 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2097 const int out_num =
2098 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2099 const double expected_snr =
2100 file_direction ? expected_reverse_snr_ : expected_snr_;
2101
2102 const int min_ref_rate = std::min(in_rate, out_rate);
2103 int ref_rate;
2104
2105 if (min_ref_rate > 32000) {
2106 ref_rate = 48000;
2107 } else if (min_ref_rate > 16000) {
2108 ref_rate = 32000;
2109 } else if (min_ref_rate > 8000) {
2110 ref_rate = 16000;
2111 } else {
2112 ref_rate = 8000;
2113 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002114
ekmeyerson60d9b332015-08-14 10:35:55 -07002115 FILE* out_file = fopen(
2116 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2117 reverse_output_rate_, cf[i].num_input,
2118 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002119 cf[i].num_reverse_output, file_direction)
2120 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002121 "rb");
2122 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002123 FILE* ref_file =
2124 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2125 cf[i].num_output, cf[i].num_output,
2126 cf[i].num_reverse_output,
2127 cf[i].num_reverse_output, file_direction)
2128 .c_str(),
2129 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002130 ASSERT_TRUE(out_file != NULL);
2131 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002132
pkasting25702cb2016-01-08 13:50:27 -08002133 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2134 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002135 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002136 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002137 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002138 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002139 // Data from the resampled output, in case the reference and output rates
2140 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002141 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002142
ekmeyerson60d9b332015-08-14 10:35:55 -07002143 PushResampler<float> resampler;
2144 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002145
ekmeyerson60d9b332015-08-14 10:35:55 -07002146 // Compute the resampling delay of the output relative to the reference,
2147 // to find the region over which we should search for the best SNR.
2148 float expected_delay_sec = 0;
2149 if (in_rate != ref_rate) {
2150 // Input resampling delay.
2151 expected_delay_sec +=
2152 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2153 }
2154 if (out_rate != ref_rate) {
2155 // Output resampling delay.
2156 expected_delay_sec +=
2157 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2158 // Delay of converting the output back to its processing rate for
2159 // testing.
2160 expected_delay_sec +=
2161 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2162 }
2163 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002164 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002165
ekmeyerson60d9b332015-08-14 10:35:55 -07002166 double variance = 0;
2167 double sq_error = 0;
2168 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2169 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2170 float* out_ptr = out_data.get();
2171 if (out_rate != ref_rate) {
2172 // Resample the output back to its internal processing rate if
2173 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002174 ASSERT_EQ(ref_length,
2175 static_cast<size_t>(resampler.Resample(
2176 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002177 out_ptr = cmp_data.get();
2178 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002179
Artem Titov0b489302021-07-28 20:50:03 +02002180 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002181 // SNR of reference vs output.
2182 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2183 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002184 }
2185
ekmeyerson60d9b332015-08-14 10:35:55 -07002186 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2187 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2188 << cf[i].num_input << ", " << cf[i].num_output << ", "
2189 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2190 << ", " << file_direction << "): ";
2191 if (sq_error > 0) {
2192 double snr = 10 * log10(variance / sq_error);
2193 EXPECT_GE(snr, expected_snr);
2194 EXPECT_NE(0, expected_snr);
2195 std::cout << "SNR=" << snr << " dB" << std::endl;
2196 } else {
aluebs776593b2016-03-15 14:04:58 -07002197 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002198 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002199
ekmeyerson60d9b332015-08-14 10:35:55 -07002200 fclose(out_file);
2201 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002202 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002203 }
2204}
2205
2206#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002207INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002208 CommonFormats,
2209 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002210 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2211 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2212 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2213 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2214 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2215 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2216 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2217 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2218 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2219 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2220 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2221 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002222
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002223 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2224 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2225 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2226 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2227 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2228 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2229 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2230 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2231 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2232 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2233 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2234 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002235
Per Åhgrenc0424252019-12-10 13:04:15 +01002236 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2237 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2238 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002239 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2240 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2241 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2242 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2243 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002244 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002245 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2246 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2247 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002248
Per Åhgrenc0424252019-12-10 13:04:15 +01002249 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2250 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2251 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002252 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2253 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2254 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2255 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2256 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2257 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2258 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002259 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002260 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002261
2262#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002263INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002264 CommonFormats,
2265 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002266 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2267 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2268 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002269 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2270 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2271 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002272 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2273 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2274 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002275 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2276 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2277 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002278
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002279 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2280 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2281 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2282 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2283 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2284 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002285 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2286 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2287 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2288 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2289 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2290 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002291
Per Åhgrenc0424252019-12-10 13:04:15 +01002292 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2293 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2294 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002295 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2296 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2297 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002298 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002299 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002300 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002301 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2302 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2303 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002304
Per Åhgrenc0424252019-12-10 13:04:15 +01002305 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2306 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2307 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002308 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2309 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2310 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002311 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002312 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002313 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002314 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2315 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002316 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002317#endif
2318
Per Åhgren3e8bf282019-08-29 23:38:40 +02002319// Produces a scoped trace debug output.
2320std::string ProduceDebugText(int render_input_sample_rate_hz,
2321 int render_output_sample_rate_hz,
2322 int capture_input_sample_rate_hz,
2323 int capture_output_sample_rate_hz,
2324 size_t render_input_num_channels,
2325 size_t render_output_num_channels,
2326 size_t capture_input_num_channels,
2327 size_t capture_output_num_channels) {
2328 rtc::StringBuilder ss;
2329 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002330 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002331 << render_input_sample_rate_hz
2332 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002333 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002334 << render_output_sample_rate_hz
2335 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002336 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002337 << capture_input_sample_rate_hz
2338 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002339 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002340 << capture_output_sample_rate_hz
2341 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002342 "\nNumber of channels:"
2343 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002344 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002345 << "\n Render output: " << render_output_num_channels
2346 << "\n Capture input: " << capture_input_num_channels
2347 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002348 return ss.Release();
2349}
2350
2351// Validates that running the audio processing module using various combinations
2352// of sample rates and number of channels works as intended.
2353void RunApmRateAndChannelTest(
2354 rtc::ArrayView<const int> sample_rates_hz,
2355 rtc::ArrayView<const int> render_channel_counts,
2356 rtc::ArrayView<const int> capture_channel_counts) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002357 rtc::scoped_refptr<AudioProcessing> apm =
2358 AudioProcessingBuilderForTesting().Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002359 webrtc::AudioProcessing::Config apm_config;
2360 apm_config.echo_canceller.enabled = true;
2361 apm->ApplyConfig(apm_config);
2362
2363 StreamConfig render_input_stream_config;
2364 StreamConfig render_output_stream_config;
2365 StreamConfig capture_input_stream_config;
2366 StreamConfig capture_output_stream_config;
2367
2368 std::vector<float> render_input_frame_channels;
2369 std::vector<float*> render_input_frame;
2370 std::vector<float> render_output_frame_channels;
2371 std::vector<float*> render_output_frame;
2372 std::vector<float> capture_input_frame_channels;
2373 std::vector<float*> capture_input_frame;
2374 std::vector<float> capture_output_frame_channels;
2375 std::vector<float*> capture_output_frame;
2376
2377 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2378 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2379 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2380 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2381 for (size_t render_input_num_channels : render_channel_counts) {
2382 for (size_t capture_input_num_channels : capture_channel_counts) {
2383 size_t render_output_num_channels = render_input_num_channels;
2384 size_t capture_output_num_channels = capture_input_num_channels;
2385 auto populate_audio_frame = [](int sample_rate_hz,
2386 size_t num_channels,
2387 StreamConfig* cfg,
2388 std::vector<float>* channels_data,
2389 std::vector<float*>* frame_data) {
2390 cfg->set_sample_rate_hz(sample_rate_hz);
2391 cfg->set_num_channels(num_channels);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002392
2393 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2394 channels_data->resize(num_channels * max_frame_size);
2395 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2396 frame_data->resize(num_channels);
2397 for (size_t channel = 0; channel < num_channels; ++channel) {
2398 (*frame_data)[channel] =
2399 &(*channels_data)[channel * max_frame_size];
2400 }
2401 };
2402
2403 populate_audio_frame(
2404 render_input_sample_rate_hz, render_input_num_channels,
2405 &render_input_stream_config, &render_input_frame_channels,
2406 &render_input_frame);
2407 populate_audio_frame(
2408 render_output_sample_rate_hz, render_output_num_channels,
2409 &render_output_stream_config, &render_output_frame_channels,
2410 &render_output_frame);
2411 populate_audio_frame(
2412 capture_input_sample_rate_hz, capture_input_num_channels,
2413 &capture_input_stream_config, &capture_input_frame_channels,
2414 &capture_input_frame);
2415 populate_audio_frame(
2416 capture_output_sample_rate_hz, capture_output_num_channels,
2417 &capture_output_stream_config, &capture_output_frame_channels,
2418 &capture_output_frame);
2419
2420 for (size_t frame = 0; frame < 2; ++frame) {
2421 SCOPED_TRACE(ProduceDebugText(
2422 render_input_sample_rate_hz, render_output_sample_rate_hz,
2423 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2424 render_input_num_channels, render_output_num_channels,
2425 render_input_num_channels, capture_output_num_channels));
2426
2427 int result = apm->ProcessReverseStream(
2428 &render_input_frame[0], render_input_stream_config,
2429 render_output_stream_config, &render_output_frame[0]);
2430 EXPECT_EQ(result, AudioProcessing::kNoError);
2431 result = apm->ProcessStream(
2432 &capture_input_frame[0], capture_input_stream_config,
2433 capture_output_stream_config, &capture_output_frame[0]);
2434 EXPECT_EQ(result, AudioProcessing::kNoError);
2435 }
2436 }
2437 }
2438 }
2439 }
2440 }
2441 }
2442}
2443
Alessio Bazzica3438a932020-10-14 12:47:50 +02002444constexpr void Toggle(bool& b) {
2445 b ^= true;
2446}
2447
niklase@google.com470e71d2011-07-07 08:21:25 +00002448} // namespace
peahc19f3122016-10-07 14:54:10 -07002449
Alessio Bazzicac054e782018-04-16 12:10:09 +02002450TEST(RuntimeSettingTest, TestDefaultCtor) {
2451 auto s = AudioProcessing::RuntimeSetting();
2452 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2453}
2454
Alessio Bazzicac054e782018-04-16 12:10:09 +02002455TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2456 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2457 auto s = AudioProcessing::RuntimeSetting();
2458 ASSERT_TRUE(q.Insert(&s));
2459 ASSERT_TRUE(q.Remove(&s));
2460 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2461}
2462
Sam Zackrisson0beac582017-09-25 12:04:02 +02002463TEST(ApmConfiguration, EnablePostProcessing) {
2464 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002465 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002466 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002467 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002468 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002469 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002470 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002471 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002472 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002473
Per Åhgren2507f8c2020-03-19 12:33:29 +01002474 Int16FrameData audio;
2475 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002476 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2477
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002478 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002479 apm->ProcessStream(audio.data.data(),
2480 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2481 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002482 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002483}
2484
Alex Loiko5825aa62017-12-18 16:02:40 +01002485TEST(ApmConfiguration, EnablePreProcessing) {
2486 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002487 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002488 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002489 auto mock_pre_processor =
2490 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002491 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002492 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002493 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002494 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002495
Per Åhgren2507f8c2020-03-19 12:33:29 +01002496 Int16FrameData audio;
2497 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002498 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2499
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002500 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002501 apm->ProcessReverseStream(
2502 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2503 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2504 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002505}
2506
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002507TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2508 // Verify that apm uses a capture analyzer if one is provided.
2509 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002510 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002511 auto mock_capture_analyzer =
2512 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2513 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002514 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002515 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2516 .Create();
2517
Per Åhgren2507f8c2020-03-19 12:33:29 +01002518 Int16FrameData audio;
2519 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002520 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2521
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002522 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002523 apm->ProcessStream(audio.data.data(),
2524 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2525 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002526 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002527}
2528
Alex Loiko73ec0192018-05-15 10:52:28 +02002529TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2530 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002531 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002532 auto mock_pre_processor =
2533 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2534 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002535 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002536 .SetRenderPreProcessing(std::move(mock_pre_processor))
2537 .Create();
2538 apm->SetRuntimeSetting(
2539 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2540
2541 // RuntimeSettings forwarded during 'Process*Stream' calls.
2542 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002543 Int16FrameData audio;
2544 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002545 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2546
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002547 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2548 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002549 apm->ProcessReverseStream(
2550 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2551 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2552 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002553}
2554
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002555class MyEchoControlFactory : public EchoControlFactory {
2556 public:
2557 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2558 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002559 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2560 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002561 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2562 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002563 return std::unique_ptr<EchoControl>(ec);
2564 }
Per Åhgrence202a02019-09-02 17:01:19 +02002565
2566 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002567 int num_render_channels,
2568 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002569 return Create(sample_rate_hz);
2570 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002571};
2572
2573TEST(ApmConfiguration, EchoControlInjection) {
2574 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002575 std::unique_ptr<EchoControlFactory> echo_control_factory(
2576 new MyEchoControlFactory());
2577
Alex Loiko5825aa62017-12-18 16:02:40 +01002578 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002579 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002580 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002581 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002582
Per Åhgren2507f8c2020-03-19 12:33:29 +01002583 Int16FrameData audio;
2584 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002585 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002586 apm->ProcessStream(audio.data.data(),
2587 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2588 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002589 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002590 apm->ProcessReverseStream(
2591 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2592 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2593 audio.data.data());
2594 apm->ProcessStream(audio.data.data(),
2595 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2596 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002597 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002598}
Ivo Creusenae026092017-11-20 13:07:16 +01002599
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002600TEST(ApmConfiguration, EchoDetectorInjection) {
2601 using ::testing::_;
2602 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2603 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2604 EXPECT_CALL(*mock_echo_detector,
2605 Initialize(/*capture_sample_rate_hz=*/16000, _,
2606 /*render_sample_rate_hz=*/16000, _))
2607 .Times(1);
Niels Möller4f776ac2021-07-02 11:30:54 +02002608 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002609 AudioProcessingBuilderForTesting()
2610 .SetEchoDetector(mock_echo_detector)
2611 .Create();
2612
2613 // The echo detector is included in processing when enabled.
2614 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2615 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2616 EXPECT_EQ(render_audio.size(), 160u);
2617 });
2618 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2619 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2620 EXPECT_EQ(capture_audio.size(), 160u);
2621 });
2622 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2623
2624 Int16FrameData frame;
2625 frame.num_channels = 1;
2626 SetFrameSampleRate(&frame, 16000);
2627
2628 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2629 StreamConfig(16000, 1), frame.data.data());
2630 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2631 StreamConfig(16000, 1), frame.data.data());
2632
2633 // When processing rates change, the echo detector is also reinitialized to
2634 // match those.
2635 EXPECT_CALL(*mock_echo_detector,
2636 Initialize(/*capture_sample_rate_hz=*/48000, _,
2637 /*render_sample_rate_hz=*/16000, _))
2638 .Times(1);
2639 EXPECT_CALL(*mock_echo_detector,
2640 Initialize(/*capture_sample_rate_hz=*/48000, _,
2641 /*render_sample_rate_hz=*/48000, _))
2642 .Times(1);
2643 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2644 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2645 EXPECT_EQ(render_audio.size(), 480u);
2646 });
2647 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2648 .Times(2)
2649 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2650 EXPECT_EQ(capture_audio.size(), 480u);
2651 });
2652 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2653
2654 SetFrameSampleRate(&frame, 48000);
2655 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2656 StreamConfig(48000, 1), frame.data.data());
2657 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2658 StreamConfig(48000, 1), frame.data.data());
2659 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2660 StreamConfig(48000, 1), frame.data.data());
2661}
2662
2663rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2664 // Enable residual echo detection, for stats.
2665 rtc::scoped_refptr<AudioProcessing> apm =
2666 AudioProcessingBuilderForTesting()
2667 .SetEchoDetector(CreateEchoDetector())
2668 .Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002669 if (!apm) {
2670 return apm;
2671 }
2672
2673 ProcessingConfig processing_config = {
2674 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2675
2676 if (apm->Initialize(processing_config) != 0) {
2677 return nullptr;
2678 }
2679
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002680 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002681 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002682 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002683 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002684 apm_config.gain_controller2.enabled = false;
2685 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002686 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002687 apm_config.noise_suppression.enabled = false;
Henrik Boström09aaf6f2022-02-14 12:02:45 +00002688 apm_config.voice_detection.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002689 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002690 return apm;
2691}
2692
2693#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2694#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2695#else
2696#define MAYBE_ApmStatistics ApmStatistics
2697#endif
2698
Per Åhgren8607f842019-04-12 22:02:26 +02002699TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2700 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002701 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002702 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002703 AudioProcessing::Config apm_config;
2704 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002705 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002706
2707 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002708 Int16FrameData frame;
2709 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002710 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002711
2712 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002713 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002714 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2715 ptr[i] = 10000 * ((i % 3) - 1);
2716 }
2717
2718 // Do some processing.
2719 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002720 EXPECT_EQ(apm->ProcessReverseStream(
2721 frame.data.data(),
2722 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2723 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2724 frame.data.data()),
2725 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002726 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002727 EXPECT_EQ(apm->ProcessStream(
2728 frame.data.data(),
2729 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2730 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002731 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002732 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002733 }
2734
2735 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002736 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002737 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002738 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002739 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2740 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002741 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002742 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2743 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002744 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002745 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002746 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002747 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002748}
2749
2750TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2751 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002752 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002753 ASSERT_TRUE(apm);
2754
2755 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002756 Int16FrameData frame;
2757 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002758 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002759
2760 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002761 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002762 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2763 ptr[i] = 10000 * ((i % 3) - 1);
2764 }
2765
2766 // Do some processing.
2767 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002768 EXPECT_EQ(apm->ProcessReverseStream(
2769 frame.data.data(),
2770 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2771 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2772 frame.data.data()),
2773 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002774 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002775 EXPECT_EQ(apm->ProcessStream(
2776 frame.data.data(),
2777 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2778 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002779 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002780 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002781 }
2782
2783 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002784 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002785 // We expect only the residual echo detector statistics to be set and have a
2786 // sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002787 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2788 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2789 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2790 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2791 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2792 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2793 EXPECT_FALSE(stats.echo_return_loss.has_value());
2794 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002795}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002796
Henrik Boström09aaf6f2022-02-14 12:02:45 +00002797TEST(ApmStatistics, ReportHasVoice) {
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002798 ProcessingConfig processing_config = {
2799 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Henrik Boström09aaf6f2022-02-14 12:02:45 +00002800 AudioProcessing::Config config;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002801
2802 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002803 Int16FrameData frame;
2804 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002805 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2806
2807 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002808 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002809 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2810 ptr[i] = 10000 * ((i % 3) - 1);
2811 }
2812
Niels Möller4f776ac2021-07-02 11:30:54 +02002813 rtc::scoped_refptr<AudioProcessing> apm =
2814 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002815 apm->Initialize(processing_config);
2816
Henrik Boström09aaf6f2022-02-14 12:02:45 +00002817 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002818 EXPECT_EQ(
2819 apm->ProcessStream(frame.data.data(),
2820 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2821 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002822 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002823 0);
Henrik Boström09aaf6f2022-02-14 12:02:45 +00002824 EXPECT_FALSE(apm->GetStatistics().voice_detected);
2825
2826 // If enabled, metrics should be reported.
2827 config.voice_detection.enabled = true;
2828 apm->ApplyConfig(config);
2829 EXPECT_EQ(
2830 apm->ProcessStream(frame.data.data(),
2831 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2832 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2833 frame.data.data()),
2834 0);
2835 auto stats = apm->GetStatistics();
2836 EXPECT_TRUE(stats.voice_detected);
2837
2838 // If re-disabled, the value is again not reported.
2839 config.voice_detection.enabled = false;
2840 apm->ApplyConfig(config);
2841 EXPECT_EQ(
2842 apm->ProcessStream(frame.data.data(),
2843 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2844 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2845 frame.data.data()),
2846 0);
2847 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002848}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002849
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002850TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2851 rtc::scoped_refptr<AudioProcessing> apm =
2852 AudioProcessingBuilderForTesting().Create();
2853 Int16FrameData frame;
2854 frame.num_channels = 1;
2855 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2856 ASSERT_EQ(
2857 apm->ProcessStream(frame.data.data(),
2858 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2859 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2860 frame.data.data()),
2861 0);
2862 // Echo detector is disabled by default, no stats reported.
2863 AudioProcessingStats stats = apm->GetStatistics();
2864 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2865 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2866}
2867
2868TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2869 // Create APM with an echo detector injected.
2870 rtc::scoped_refptr<AudioProcessing> apm =
2871 AudioProcessingBuilderForTesting()
2872 .SetEchoDetector(CreateEchoDetector())
2873 .Create();
2874 Int16FrameData frame;
2875 frame.num_channels = 1;
2876 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2877 // Echo detector enabled: Report stats.
2878 ASSERT_EQ(
2879 apm->ProcessStream(frame.data.data(),
2880 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2881 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2882 frame.data.data()),
2883 0);
2884 AudioProcessingStats stats = apm->GetStatistics();
2885 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2886 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2887}
2888
Per Åhgren3e8bf282019-08-29 23:38:40 +02002889TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2890 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2891 std::array<int, 2> render_channel_counts = {1, 7};
2892 std::array<int, 2> capture_channel_counts = {1, 7};
2893 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2894 capture_channel_counts);
2895}
2896
2897TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2898 std::array<int, 1> sample_rates_hz = {48000};
2899 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2900 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2901 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2902 capture_channel_counts);
2903}
2904
2905TEST(ApmConfiguration, HandlingOfRateCombinations) {
2906 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2907 48000, 96000, 192000, 384000};
2908 std::array<int, 1> render_channel_counts = {2};
2909 std::array<int, 1> capture_channel_counts = {2};
2910 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2911 capture_channel_counts);
2912}
2913
Yves Gerey1fce3f82019-12-05 17:45:31 +01002914TEST(ApmConfiguration, SelfAssignment) {
2915 // At some point memory sanitizer was complaining about self-assigment.
2916 // Make sure we don't regress.
2917 AudioProcessing::Config config;
2918 AudioProcessing::Config* config2 = &config;
2919 *config2 = *config2; // Workaround -Wself-assign-overloaded
2920 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2921}
2922
Alessio Bazzica3438a932020-10-14 12:47:50 +02002923TEST(AudioProcessing, GainController1ConfigEqual) {
2924 AudioProcessing::Config::GainController1 a;
2925 AudioProcessing::Config::GainController1 b;
2926 EXPECT_EQ(a, b);
2927
2928 Toggle(a.enabled);
2929 b.enabled = a.enabled;
2930 EXPECT_EQ(a, b);
2931
2932 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2933 b.mode = a.mode;
2934 EXPECT_EQ(a, b);
2935
2936 a.target_level_dbfs++;
2937 b.target_level_dbfs = a.target_level_dbfs;
2938 EXPECT_EQ(a, b);
2939
2940 a.compression_gain_db++;
2941 b.compression_gain_db = a.compression_gain_db;
2942 EXPECT_EQ(a, b);
2943
2944 Toggle(a.enable_limiter);
2945 b.enable_limiter = a.enable_limiter;
2946 EXPECT_EQ(a, b);
2947
Alessio Bazzica3438a932020-10-14 12:47:50 +02002948 auto& a_analog = a.analog_gain_controller;
2949 auto& b_analog = b.analog_gain_controller;
2950
2951 Toggle(a_analog.enabled);
2952 b_analog.enabled = a_analog.enabled;
2953 EXPECT_EQ(a, b);
2954
2955 a_analog.startup_min_volume++;
2956 b_analog.startup_min_volume = a_analog.startup_min_volume;
2957 EXPECT_EQ(a, b);
2958
2959 a_analog.clipped_level_min++;
2960 b_analog.clipped_level_min = a_analog.clipped_level_min;
2961 EXPECT_EQ(a, b);
2962
Alessio Bazzica3438a932020-10-14 12:47:50 +02002963 Toggle(a_analog.enable_digital_adaptive);
2964 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2965 EXPECT_EQ(a, b);
2966}
2967
2968// Checks that one differing parameter is sufficient to make two configs
2969// different.
2970TEST(AudioProcessing, GainController1ConfigNotEqual) {
2971 AudioProcessing::Config::GainController1 a;
2972 const AudioProcessing::Config::GainController1 b;
2973
2974 Toggle(a.enabled);
2975 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002976 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002977
2978 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2979 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002980 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002981
2982 a.target_level_dbfs++;
2983 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002984 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002985
2986 a.compression_gain_db++;
2987 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002988 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002989
2990 Toggle(a.enable_limiter);
2991 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002992 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002993
Alessio Bazzica3438a932020-10-14 12:47:50 +02002994 auto& a_analog = a.analog_gain_controller;
2995 const auto& b_analog = b.analog_gain_controller;
2996
2997 Toggle(a_analog.enabled);
2998 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002999 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003000
3001 a_analog.startup_min_volume++;
3002 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003003 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003004
3005 a_analog.clipped_level_min++;
3006 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003007 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003008
Alessio Bazzica3438a932020-10-14 12:47:50 +02003009 Toggle(a_analog.enable_digital_adaptive);
3010 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003011 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003012}
3013
3014TEST(AudioProcessing, GainController2ConfigEqual) {
3015 AudioProcessing::Config::GainController2 a;
3016 AudioProcessing::Config::GainController2 b;
3017 EXPECT_EQ(a, b);
3018
3019 Toggle(a.enabled);
3020 b.enabled = a.enabled;
3021 EXPECT_EQ(a, b);
3022
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003023 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003024 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3025 EXPECT_EQ(a, b);
3026
3027 auto& a_adaptive = a.adaptive_digital;
3028 auto& b_adaptive = b.adaptive_digital;
3029
3030 Toggle(a_adaptive.enabled);
3031 b_adaptive.enabled = a_adaptive.enabled;
3032 EXPECT_EQ(a, b);
3033
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003034 Toggle(a_adaptive.dry_run);
3035 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003036 EXPECT_EQ(a, b);
3037
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003038 a_adaptive.headroom_db += 1.0f;
3039 b_adaptive.headroom_db = a_adaptive.headroom_db;
3040 EXPECT_EQ(a, b);
3041
3042 a_adaptive.max_gain_db += 1.0f;
3043 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3044 EXPECT_EQ(a, b);
3045
3046 a_adaptive.initial_gain_db += 1.0f;
3047 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3048 EXPECT_EQ(a, b);
3049
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003050 a_adaptive.vad_reset_period_ms++;
3051 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003052 EXPECT_EQ(a, b);
3053
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003054 a_adaptive.adjacent_speech_frames_threshold++;
3055 b_adaptive.adjacent_speech_frames_threshold =
3056 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003057 EXPECT_EQ(a, b);
3058
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003059 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003060 b_adaptive.max_gain_change_db_per_second =
3061 a_adaptive.max_gain_change_db_per_second;
3062 EXPECT_EQ(a, b);
3063
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003064 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003065 b_adaptive.max_output_noise_level_dbfs =
3066 a_adaptive.max_output_noise_level_dbfs;
3067 EXPECT_EQ(a, b);
3068}
3069
3070// Checks that one differing parameter is sufficient to make two configs
3071// different.
3072TEST(AudioProcessing, GainController2ConfigNotEqual) {
3073 AudioProcessing::Config::GainController2 a;
3074 const AudioProcessing::Config::GainController2 b;
3075
3076 Toggle(a.enabled);
3077 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003078 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003079
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003080 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003081 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003082 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003083
3084 auto& a_adaptive = a.adaptive_digital;
3085 const auto& b_adaptive = b.adaptive_digital;
3086
3087 Toggle(a_adaptive.enabled);
3088 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003089 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003090
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003091 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003092 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003093 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003094
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003095 a_adaptive.headroom_db += 1.0f;
3096 EXPECT_NE(a, b);
3097 a_adaptive = b_adaptive;
3098
3099 a_adaptive.max_gain_db += 1.0f;
3100 EXPECT_NE(a, b);
3101 a_adaptive = b_adaptive;
3102
3103 a_adaptive.initial_gain_db += 1.0f;
3104 EXPECT_NE(a, b);
3105 a_adaptive = b_adaptive;
3106
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003107 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003108 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003109 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003110
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003111 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003112 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003113 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003114
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003115 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003116 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003117 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003118
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003119 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003120 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003121 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003122}
3123
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003124} // namespace webrtc