blob: 2a91b6a067badf9389c5c80a61705882d6bc5f26 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "common_audio/include/audio_util.h"
24#include "common_audio/resampler/include/push_resampler.h"
25#include "common_audio/resampler/push_sinc_resampler.h"
26#include "common_audio/signal_processing/include/signal_processing_library.h"
27#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
28#include "modules/audio_processing/audio_processing_impl.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020029#include "modules/audio_processing/common.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
andrew@webrtc.org103657b2014-04-24 18:28:56 +000097// Number of channels including the keyboard channel.
Peter Kasting69558702016-01-12 16:26:35 -080098size_t TotalChannelsFromLayout(AudioProcessing::ChannelLayout layout) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +000099 switch (layout) {
100 case AudioProcessing::kMono:
101 return 1;
102 case AudioProcessing::kMonoAndKeyboard:
103 case AudioProcessing::kStereo:
104 return 2;
105 case AudioProcessing::kStereoAndKeyboard:
106 return 3;
107 }
Artem Titovd3251962021-11-15 16:57:07 +0100108 RTC_DCHECK_NOTREACHED();
pkasting25702cb2016-01-08 13:50:27 -0800109 return 0;
andrew@webrtc.org103657b2014-04-24 18:28:56 +0000110}
111
Jonas Olssona4d87372019-07-05 19:08:33 +0200112void MixStereoToMono(const float* stereo,
113 float* mono,
pkasting25702cb2016-01-08 13:50:27 -0800114 size_t samples_per_channel) {
115 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000116 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000117}
118
Jonas Olssona4d87372019-07-05 19:08:33 +0200119void MixStereoToMono(const int16_t* stereo,
120 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -0800121 size_t samples_per_channel) {
122 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000123 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
124}
125
pkasting25702cb2016-01-08 13:50:27 -0800126void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
127 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000128 stereo[i * 2 + 1] = stereo[i * 2];
129 }
130}
131
yujo36b1a5f2017-06-12 12:45:32 -0700132void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800133 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000134 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
135 }
136}
137
Per Åhgren2507f8c2020-03-19 12:33:29 +0100138void SetFrameTo(Int16FrameData* frame, int16_t value) {
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] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000142 }
143}
144
Per Åhgren2507f8c2020-03-19 12:33:29 +0100145void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
146 ASSERT_EQ(2u, frame->num_channels);
147 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
148 frame->data[i] = left;
149 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000150 }
151}
152
Per Åhgren2507f8c2020-03-19 12:33:29 +0100153void ScaleFrame(Int16FrameData* frame, float scale) {
154 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700155 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100156 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000157 }
158}
159
Per Åhgren2507f8c2020-03-19 12:33:29 +0100160bool FrameDataAreEqual(const Int16FrameData& frame1,
161 const Int16FrameData& frame2) {
162 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000163 return false;
164 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100165 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000166 return false;
167 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100168 if (memcmp(
169 frame1.data.data(), frame2.data.data(),
170 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000171 return false;
172 }
173 return true;
174}
175
Per Åhgren2507f8c2020-03-19 12:33:29 +0100176rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
177 int16_t* ptr = frame->data.data();
178 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200179 return rtc::ArrayView<int16_t>(ptr, len);
180}
181
Per Åhgren2507f8c2020-03-19 12:33:29 +0100182rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
183 const int16_t* ptr = frame.data.data();
184 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200185 return rtc::ArrayView<const int16_t>(ptr, len);
186}
187
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000188void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200189 AudioProcessing::Config apm_config = ap->GetConfig();
190 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000191#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200192 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100193
194 apm_config.gain_controller1.enabled = true;
195 apm_config.gain_controller1.mode =
196 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000197#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200198 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000199
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100200 apm_config.gain_controller1.enabled = true;
201 apm_config.gain_controller1.mode =
202 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000203#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000204
saza0bad15f2019-10-16 11:46:11 +0200205 apm_config.noise_suppression.enabled = true;
206
peah8271d042016-11-22 07:24:52 -0800207 apm_config.high_pass_filter.enabled = true;
Sam Zackrisson0824c6f2019-10-07 14:03:56 +0200208 apm_config.voice_detection.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100209 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800210 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000211}
212
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000213// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000214template <class T>
215T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200216 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000217}
218
Per Åhgren2507f8c2020-03-19 12:33:29 +0100219int16_t MaxAudioFrame(const Int16FrameData& frame) {
220 const size_t length = frame.samples_per_channel * frame.num_channels;
221 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800222 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100223 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000224 }
225
226 return max_data;
227}
228
Alex Loiko890988c2017-08-31 10:25:48 +0200229void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700230 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000231 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000232 ASSERT_TRUE(file != NULL);
233
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100234 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000235 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800236 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000237 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000238
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000239 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000240 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200241 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000242 fclose(file);
243}
244
Alex Loiko890988c2017-08-31 10:25:48 +0200245std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200246 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000247 // Resource files are all stereo.
248 ss << name << sample_rate_hz / 1000 << "_stereo";
249 return test::ResourcePath(ss.str(), "pcm");
250}
251
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000252// Temporary filenames unique to this process. Used to be able to run these
253// tests in parallel as each process needs to be running in isolation they can't
254// have competing filenames.
255std::map<std::string, std::string> temp_filenames;
256
Alex Loiko890988c2017-08-31 10:25:48 +0200257std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000258 int input_rate,
259 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700260 int reverse_input_rate,
261 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800262 size_t num_input_channels,
263 size_t num_output_channels,
264 size_t num_reverse_input_channels,
265 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700266 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200267 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700268 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
269 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000270 if (num_output_channels == 1) {
271 ss << "mono";
272 } else if (num_output_channels == 2) {
273 ss << "stereo";
274 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100275 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000276 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700277 ss << output_rate / 1000;
278 if (num_reverse_output_channels == 1) {
279 ss << "_rmono";
280 } else if (num_reverse_output_channels == 2) {
281 ss << "_rstereo";
282 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100283 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700284 }
285 ss << reverse_output_rate / 1000;
286 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000287
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000288 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700289 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000290 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
291 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000292}
293
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000294void ClearTempFiles() {
295 for (auto& kv : temp_filenames)
296 remove(kv.second.c_str());
297}
298
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200299// Only remove "out" files. Keep "ref" files.
300void ClearTempOutFiles() {
301 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
302 const std::string& filename = it->first;
303 if (filename.substr(0, 3).compare("out") == 0) {
304 remove(it->second.c_str());
305 temp_filenames.erase(it++);
306 } else {
307 it++;
308 }
309 }
310}
311
Alex Loiko890988c2017-08-31 10:25:48 +0200312void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000313 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000314 ASSERT_TRUE(file != NULL);
315 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000316 fclose(file);
317}
318
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000319// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
320// stereo) file, converts to deinterleaved float (optionally downmixing) and
Artem Titov0b489302021-07-28 20:50:03 +0200321// returns the result in `cb`. Returns false if the file ended (or on error) and
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000322// true otherwise.
323//
Artem Titov0b489302021-07-28 20:50:03 +0200324// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000325// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200326bool ReadChunk(FILE* file,
327 int16_t* int_data,
328 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000329 ChannelBuffer<float>* cb) {
330 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000331 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000332 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
333 if (read_count != frame_size) {
334 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700335 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000336 return false; // This is expected.
337 }
338
339 S16ToFloat(int_data, frame_size, float_data);
340 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000341 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000342 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200343 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000344 }
345
346 return true;
347}
348
Per Åhgrena43178c2020-09-25 12:02:32 +0200349// Returns the reference file name that matches the current CPU
350// architecture/optimizations.
351std::string GetReferenceFilename() {
352#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
353 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
354#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
355 if (GetCPUInfo(kAVX2) != 0) {
356 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
357 }
358 return test::ResourcePath("audio_processing/output_data_float", "pb");
359#endif
360}
361
niklase@google.com470e71d2011-07-07 08:21:25 +0000362class ApmTest : public ::testing::Test {
363 protected:
364 ApmTest();
365 virtual void SetUp();
366 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000367
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200368 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000369
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200370 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000371
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000372 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200373 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000374
375 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000376 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000377 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800378 size_t num_input_channels,
379 size_t num_output_channels,
380 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000381 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000382 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000383 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100384 bool ReadFrame(FILE* file, Int16FrameData* frame);
385 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
386 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200387 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100388 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000389 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200390 void ProcessDelayVerificationTest(int delay_ms,
391 int system_delay_ms,
392 int delay_min,
393 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700394 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800395 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700396 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800397 void TestChangingForwardChannels(size_t num_in_channels,
398 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700399 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800400 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700401 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000402 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
403 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000404 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000405 int ProcessStreamChooser(Format format);
406 int AnalyzeReverseStreamChooser(Format format);
407 void ProcessDebugDump(const std::string& in_filename,
408 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800409 Format format,
410 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000411 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000412
413 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000414 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200415 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100416 Int16FrameData frame_;
417 Int16FrameData revframe_;
kwiberg62eaacf2016-02-17 06:39:05 -0800418 std::unique_ptr<ChannelBuffer<float> > float_cb_;
419 std::unique_ptr<ChannelBuffer<float> > revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000420 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800421 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 FILE* far_file_;
423 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000424 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000425};
426
427ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000428 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200429 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000430 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000431 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000432 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000433 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000434 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200435 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100436 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100437 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100438 apm_config.pipeline.maximum_internal_processing_rate = 48000;
439 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000440}
niklase@google.com470e71d2011-07-07 08:21:25 +0000441
442void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000443 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000444
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000445 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000446}
447
448void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000449 if (far_file_) {
450 ASSERT_EQ(0, fclose(far_file_));
451 }
452 far_file_ = NULL;
453
454 if (near_file_) {
455 ASSERT_EQ(0, fclose(near_file_));
456 }
457 near_file_ = NULL;
458
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000459 if (out_file_) {
460 ASSERT_EQ(0, fclose(out_file_));
461 }
462 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000463}
464
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000465void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200466 ASSERT_EQ(
467 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100468 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200469 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100470 {revframe_.sample_rate_hz, revframe_.num_channels},
471 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000472}
473
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000474void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000475 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000476 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800477 size_t num_input_channels,
478 size_t num_output_channels,
479 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000480 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200481 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000482 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000483 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000484
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200485 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000486 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000487 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000488
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000489 if (far_file_) {
490 ASSERT_EQ(0, fclose(far_file_));
491 }
492 std::string filename = ResourceFilePath("far", sample_rate_hz);
493 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200494 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000495
496 if (near_file_) {
497 ASSERT_EQ(0, fclose(near_file_));
498 }
499 filename = ResourceFilePath("near", sample_rate_hz);
500 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200501 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000502
503 if (open_output_file) {
504 if (out_file_) {
505 ASSERT_EQ(0, fclose(out_file_));
506 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700507 filename = OutputFilePath(
508 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
509 reverse_sample_rate_hz, num_input_channels, num_output_channels,
510 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000511 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200512 ASSERT_TRUE(out_file_ != NULL)
513 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000514 }
515}
516
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000517void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000518 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000519}
520
Jonas Olssona4d87372019-07-05 19:08:33 +0200521bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100522 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000523 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000524 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100525 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200526 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100527 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000528 if (read_count != frame_size) {
529 // Check that the file really ended.
530 EXPECT_NE(0, feof(file));
531 return false; // This is expected.
532 }
533
Per Åhgren2507f8c2020-03-19 12:33:29 +0100534 if (frame->num_channels == 1) {
535 MixStereoToMono(frame->data.data(), frame->data.data(),
536 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000537 }
538
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000539 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000540 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000541 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000542 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000543}
544
Per Åhgren2507f8c2020-03-19 12:33:29 +0100545bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000546 return ReadFrame(file, frame, NULL);
547}
548
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000549// If the end of the file has been reached, rewind it and attempt to read the
550// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200551void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100552 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000553 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200554 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000555 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200556 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000557 }
558}
559
Per Åhgren2507f8c2020-03-19 12:33:29 +0100560void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000561 ReadFrameWithRewind(file, frame, NULL);
562}
563
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000564int ApmTest::ProcessStreamChooser(Format format) {
565 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100566 return apm_->ProcessStream(
567 frame_.data.data(),
568 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
569 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100570 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000571 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200572 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100573 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100574 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100575 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200576 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000577}
578
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000579int ApmTest::AnalyzeReverseStreamChooser(Format format) {
580 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100581 return apm_->ProcessReverseStream(
582 revframe_.data.data(),
583 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
584 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
585 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000586 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000587 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100588 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100589 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000590}
591
Jonas Olssona4d87372019-07-05 19:08:33 +0200592void ApmTest::ProcessDelayVerificationTest(int delay_ms,
593 int system_delay_ms,
594 int delay_min,
595 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200596 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000597 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100598 Int16FrameData tmp_frame;
599 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000600 bool causal = true;
601
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200602 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000603 SetFrameTo(&tmp_frame, 0);
604
605 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200606 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000607 int frame_delay = delay_ms / 10;
608 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100609 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000610 frame->CopyFrom(tmp_frame);
611 frame_queue.push(frame);
612 frame_delay++;
613 causal = false;
614 }
615 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100616 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000617 frame->CopyFrom(tmp_frame);
618 frame_queue.push(frame);
619 frame_delay--;
620 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000621 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
622 // need enough frames with audio to have reliable estimates, but as few as
623 // possible to keep processing time down. 4.5 seconds seemed to be a good
624 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000625 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100626 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000627 frame->CopyFrom(tmp_frame);
628 // Use the near end recording, since that has more speech in it.
629 ASSERT_TRUE(ReadFrame(near_file_, frame));
630 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100631 Int16FrameData* reverse_frame = frame;
632 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000633 if (!causal) {
634 reverse_frame = frame_queue.front();
635 // When we call ProcessStream() the frame is modified, so we can't use the
636 // pointer directly when things are non-causal. Use an intermediate frame
637 // and copy the data.
638 process_frame = &tmp_frame;
639 process_frame->CopyFrom(*frame);
640 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100641 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
642 reverse_frame->data.data(),
643 StreamConfig(reverse_frame->sample_rate_hz,
644 reverse_frame->num_channels),
645 StreamConfig(reverse_frame->sample_rate_hz,
646 reverse_frame->num_channels),
647 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000648 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100649 EXPECT_EQ(apm_->kNoError,
650 apm_->ProcessStream(process_frame->data.data(),
651 StreamConfig(process_frame->sample_rate_hz,
652 process_frame->num_channels),
653 StreamConfig(process_frame->sample_rate_hz,
654 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100655 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000656 frame = frame_queue.front();
657 frame_queue.pop();
658 delete frame;
659
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000660 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000661 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100662 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000663 }
664 }
665
666 rewind(near_file_);
667 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100668 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000669 frame_queue.pop();
670 delete frame;
671 }
672 // Calculate expected delay estimate and acceptable regions. Further,
673 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700674 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100675 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700676 const int expected_median =
677 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
678 const int expected_median_high = rtc::SafeClamp<int>(
679 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700680 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700681 const int expected_median_low = rtc::SafeClamp<int>(
682 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700683 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000684 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100685 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200686 ASSERT_TRUE(stats.delay_median_ms.has_value());
687 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000688 EXPECT_GE(expected_median_high, median);
689 EXPECT_LE(expected_median_low, median);
690}
691
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000692void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000693 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000694 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000695
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000696 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200697 AudioProcessing::Config apm_config = apm_->GetConfig();
698 apm_config.gain_controller1.enabled = true;
699 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200700 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000702 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200703 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000704 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200705 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000706
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000707 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200708 apm_config.echo_canceller.enabled = true;
709 apm_config.echo_canceller.mobile_mode = false;
710 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000711 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200712 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200713 apm_config.gain_controller1.enabled = false;
714 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000715
716 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000717 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100718 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000719
720 // Resets after successful ProcessStream().
721 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000722 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100723 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000724
725 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200726 apm_config.gain_controller1.enabled = true;
727 apm_->ApplyConfig(apm_config);
728 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100729 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200730 apm_config.gain_controller1.enabled = false;
731 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000732
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000733 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200734 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100735 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000736
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000737 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000738 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200739 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000740 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000741}
742
743TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000744 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000745}
746
747TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000748 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000749}
750
Michael Graczyk86c6d332015-07-23 11:41:39 -0700751void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800752 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700753 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100754 frame_.num_channels = num_channels;
755
756 EXPECT_EQ(expected_return,
757 apm_->ProcessStream(
758 frame_.data.data(),
759 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
760 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100761 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100762 EXPECT_EQ(expected_return,
763 apm_->ProcessReverseStream(
764 frame_.data.data(),
765 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
766 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
767 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000768}
769
Michael Graczyk86c6d332015-07-23 11:41:39 -0700770void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800771 size_t num_in_channels,
772 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700773 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100774 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700775 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
776
777 EXPECT_EQ(expected_return,
778 apm_->ProcessStream(float_cb_->channels(), input_stream,
779 output_stream, float_cb_->channels()));
780}
781
782void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800783 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700784 AudioProcessing::Error expected_return) {
785 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100786 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700787 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100788 {frame_.sample_rate_hz, num_rev_channels},
789 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700790
ekmeyerson60d9b332015-08-14 10:35:55 -0700791 EXPECT_EQ(
792 expected_return,
793 apm_->ProcessReverseStream(
794 float_cb_->channels(), processing_config.reverse_input_stream(),
795 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700796}
797
798TEST_F(ApmTest, ChannelsInt16Interface) {
799 // Testing number of invalid and valid channels.
800 Init(16000, 16000, 16000, 4, 4, 4, false);
801
802 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
803
Peter Kasting69558702016-01-12 16:26:35 -0800804 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700805 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000806 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000807 }
808}
809
Michael Graczyk86c6d332015-07-23 11:41:39 -0700810TEST_F(ApmTest, Channels) {
811 // Testing number of invalid and valid channels.
812 Init(16000, 16000, 16000, 4, 4, 4, false);
813
814 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
815 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
816
Peter Kasting69558702016-01-12 16:26:35 -0800817 for (size_t i = 1; i < 4; ++i) {
818 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700819 // Output channels much be one or match input channels.
820 if (j == 1 || i == j) {
821 TestChangingForwardChannels(i, j, kNoErr);
822 TestChangingReverseChannels(i, kNoErr);
823
824 EXPECT_EQ(i, apm_->num_input_channels());
825 EXPECT_EQ(j, apm_->num_output_channels());
826 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800827 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700828 } else {
829 TestChangingForwardChannels(i, j,
830 AudioProcessing::kBadNumberChannelsError);
831 }
832 }
833 }
834}
835
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000836TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100837 // Testing some valid sample rates.
838 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
839 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000840 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000841 }
842}
843
Sam Zackrissone277bde2019-10-25 10:07:54 +0200844// This test repeatedly reconfigures the pre-amplifier in APM, processes a
845// number of frames, and checks that output signal has the right level.
846TEST_F(ApmTest, PreAmplifier) {
847 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200848 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100849 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200850 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100851 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200852 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
853 }
854 }
855 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100856 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200857 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200858
Per Åhgren2507f8c2020-03-19 12:33:29 +0100859 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200860 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
861 return std::accumulate(data.begin(), data.end(), 0.0f,
862 [](float a, float b) { return a + b * b; }) /
863 data.size() / 32768 / 32768;
864 };
865
866 const float input_power = compute_power(tmp_frame);
867 // Double-check that the input data is large compared to the error kEpsilon.
868 constexpr float kEpsilon = 1e-4f;
869 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
870
871 // 1. Enable pre-amp with 0 dB gain.
872 AudioProcessing::Config config = apm_->GetConfig();
873 config.pre_amplifier.enabled = true;
874 config.pre_amplifier.fixed_gain_factor = 1.0f;
875 apm_->ApplyConfig(config);
876
877 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200878 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200879 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
880 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200881 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200882 EXPECT_NEAR(output_power, input_power, kEpsilon);
883 config = apm_->GetConfig();
884 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
885
886 // 2. Change pre-amp gain via ApplyConfig.
887 config.pre_amplifier.fixed_gain_factor = 2.0f;
888 apm_->ApplyConfig(config);
889
890 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200891 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200892 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
893 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200894 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200895 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
896 config = apm_->GetConfig();
897 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
898
899 // 3. Change pre-amp gain via a RuntimeSetting.
900 apm_->SetRuntimeSetting(
901 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
902
903 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200904 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200905 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
906 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200907 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200908 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
909 config = apm_->GetConfig();
910 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
911}
912
Per Åhgrendb5d7282021-03-15 16:31:04 +0000913// This test a simple test that ensures that the emulated analog mic gain
914// functionality runs without crashing.
915TEST_F(ApmTest, AnalogMicGainEmulation) {
916 // Fill the audio frame with a sawtooth pattern.
917 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
918 const size_t samples_per_channel = frame_.samples_per_channel;
919 for (size_t i = 0; i < samples_per_channel; i++) {
920 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
921 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
922 }
923 }
924 // Cache the frame in tmp_frame.
925 Int16FrameData tmp_frame;
926 tmp_frame.CopyFrom(frame_);
927
928 // Enable the analog gain emulation.
929 AudioProcessing::Config config = apm_->GetConfig();
930 config.capture_level_adjustment.enabled = true;
931 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
932 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
933 config.gain_controller1.enabled = true;
934 config.gain_controller1.mode =
935 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
936 config.gain_controller1.analog_gain_controller.enabled = true;
937 apm_->ApplyConfig(config);
938
939 // Process a number of frames to ensure that the code runs without crashes.
940 for (int i = 0; i < 20; ++i) {
941 frame_.CopyFrom(tmp_frame);
942 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
943 }
944}
945
946// This test repeatedly reconfigures the capture level adjustment functionality
947// in APM, processes a number of frames, and checks that output signal has the
948// right level.
949TEST_F(ApmTest, CaptureLevelAdjustment) {
950 // Fill the audio frame with a sawtooth pattern.
951 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
952 const size_t samples_per_channel = frame_.samples_per_channel;
953 for (size_t i = 0; i < samples_per_channel; i++) {
954 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
955 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
956 }
957 }
958 // Cache the frame in tmp_frame.
959 Int16FrameData tmp_frame;
960 tmp_frame.CopyFrom(frame_);
961
962 auto compute_power = [](const Int16FrameData& frame) {
963 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
964 return std::accumulate(data.begin(), data.end(), 0.0f,
965 [](float a, float b) { return a + b * b; }) /
966 data.size() / 32768 / 32768;
967 };
968
969 const float input_power = compute_power(tmp_frame);
970 // Double-check that the input data is large compared to the error kEpsilon.
971 constexpr float kEpsilon = 1e-20f;
972 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
973
974 // 1. Enable pre-amp with 0 dB gain.
975 AudioProcessing::Config config = apm_->GetConfig();
976 config.capture_level_adjustment.enabled = true;
977 config.capture_level_adjustment.pre_gain_factor = 0.5f;
978 config.capture_level_adjustment.post_gain_factor = 4.f;
979 const float expected_output_power1 =
980 config.capture_level_adjustment.pre_gain_factor *
981 config.capture_level_adjustment.pre_gain_factor *
982 config.capture_level_adjustment.post_gain_factor *
983 config.capture_level_adjustment.post_gain_factor * input_power;
984 apm_->ApplyConfig(config);
985
986 for (int i = 0; i < 20; ++i) {
987 frame_.CopyFrom(tmp_frame);
988 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
989 }
990 float output_power = compute_power(frame_);
991 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
992 config = apm_->GetConfig();
993 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
994 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
995
996 // 2. Change pre-amp gain via ApplyConfig.
997 config.capture_level_adjustment.pre_gain_factor = 1.0f;
998 config.capture_level_adjustment.post_gain_factor = 2.f;
999 const float expected_output_power2 =
1000 config.capture_level_adjustment.pre_gain_factor *
1001 config.capture_level_adjustment.pre_gain_factor *
1002 config.capture_level_adjustment.post_gain_factor *
1003 config.capture_level_adjustment.post_gain_factor * input_power;
1004 apm_->ApplyConfig(config);
1005
1006 for (int i = 0; i < 20; ++i) {
1007 frame_.CopyFrom(tmp_frame);
1008 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1009 }
1010 output_power = compute_power(frame_);
1011 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1012 config = apm_->GetConfig();
1013 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1014 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1015
1016 // 3. Change pre-amp gain via a RuntimeSetting.
1017 constexpr float kPreGain3 = 0.5f;
1018 constexpr float kPostGain3 = 3.f;
1019 const float expected_output_power3 =
1020 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1021
1022 apm_->SetRuntimeSetting(
1023 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1024 apm_->SetRuntimeSetting(
1025 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1026
1027 for (int i = 0; i < 20; ++i) {
1028 frame_.CopyFrom(tmp_frame);
1029 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1030 }
1031 output_power = compute_power(frame_);
1032 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1033 config = apm_->GetConfig();
1034 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1035 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1036}
1037
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001038TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001039 AudioProcessing::Config config = apm_->GetConfig();
1040 config.gain_controller1.enabled = false;
1041 apm_->ApplyConfig(config);
1042 config.gain_controller1.enabled = true;
1043 apm_->ApplyConfig(config);
1044
niklase@google.com470e71d2011-07-07 08:21:25 +00001045 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001046 for (auto mode :
1047 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1048 AudioProcessing::Config::GainController1::kFixedDigital,
1049 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1050 config.gain_controller1.mode = mode;
1051 apm_->ApplyConfig(config);
1052 apm_->set_stream_analog_level(100);
1053 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001055
Sam Zackrisson41478c72019-10-15 10:10:26 +02001056 // Testing target levels
1057 for (int target_level_dbfs : {0, 15, 31}) {
1058 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1059 apm_->ApplyConfig(config);
1060 apm_->set_stream_analog_level(100);
1061 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001062 }
1063
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001064 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001065 for (int compression_gain_db : {0, 10, 90}) {
1066 config.gain_controller1.compression_gain_db = compression_gain_db;
1067 apm_->ApplyConfig(config);
1068 apm_->set_stream_analog_level(100);
1069 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001070 }
1071
1072 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001073 for (bool enable : {false, true}) {
1074 config.gain_controller1.enable_limiter = enable;
1075 apm_->ApplyConfig(config);
1076 apm_->set_stream_analog_level(100);
1077 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1078 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001079
Hanna Silencd597042021-11-02 11:02:48 +01001080 // Testing level limits.
1081 constexpr int kMinLevel = 0;
1082 constexpr int kMaxLevel = 255;
1083 apm_->set_stream_analog_level(kMinLevel);
1084 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1085 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1086 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1087 apm_->set_stream_analog_level(kMaxLevel);
1088 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001089}
1090
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001091#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001092using ApmDeathTest = ApmTest;
1093
1094TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001095 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001096 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001097 config.gain_controller1.target_level_dbfs = -1;
1098 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001099}
1100
Tommia5e07cc2020-05-26 21:40:37 +02001101TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001102 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001103 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001104 config.gain_controller1.target_level_dbfs = 32;
1105 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001106}
1107
Tommia5e07cc2020-05-26 21:40:37 +02001108TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001109 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001110 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001111 config.gain_controller1.compression_gain_db = -1;
1112 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001113}
1114
Tommia5e07cc2020-05-26 21:40:37 +02001115TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001116 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001117 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001118 config.gain_controller1.compression_gain_db = 91;
1119 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001120}
1121
Tommia5e07cc2020-05-26 21:40:37 +02001122TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001123 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001124 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001125 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001126 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001127}
1128
Tommia5e07cc2020-05-26 21:40:37 +02001129TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001130 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001131 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001132 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001133 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001134}
1135#endif
1136
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001137void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001138 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001139 auto config = apm_->GetConfig();
1140 config.gain_controller1.enabled = true;
1141 config.gain_controller1.mode =
1142 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1143 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001144
1145 int out_analog_level = 0;
1146 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001147 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001148 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001149 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001150
1151 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001152 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001153 EXPECT_EQ(apm_->kNoError,
1154 apm_->ProcessStream(
1155 frame_.data.data(),
1156 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1157 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001158 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001159 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001160 }
1161
1162 // Ensure the AGC is still able to reach the maximum.
1163 EXPECT_EQ(255, out_analog_level);
1164}
1165
1166// Verifies that despite volume slider quantization, the AGC can continue to
1167// increase its volume.
1168TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001169 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001170 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1171 }
1172}
1173
1174void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001175 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001176 auto config = apm_->GetConfig();
1177 config.gain_controller1.enabled = true;
1178 config.gain_controller1.mode =
1179 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1180 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001181
1182 int out_analog_level = 100;
1183 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001184 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001185 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001186 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001187
Sam Zackrisson41478c72019-10-15 10:10:26 +02001188 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001189 EXPECT_EQ(apm_->kNoError,
1190 apm_->ProcessStream(
1191 frame_.data.data(),
1192 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1193 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001194 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001195 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001196 }
1197
1198 // Ensure the volume was raised.
1199 EXPECT_GT(out_analog_level, 100);
1200 int highest_level_reached = out_analog_level;
1201 // Simulate a user manual volume change.
1202 out_analog_level = 100;
1203
1204 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001205 ReadFrameWithRewind(near_file_, &frame_);
1206 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001207
Sam Zackrisson41478c72019-10-15 10:10:26 +02001208 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001209 EXPECT_EQ(apm_->kNoError,
1210 apm_->ProcessStream(
1211 frame_.data.data(),
1212 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1213 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001214 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001215 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001216 // Check that AGC respected the manually adjusted volume.
1217 EXPECT_LT(out_analog_level, highest_level_reached);
1218 }
1219 // Check that the volume was still raised.
1220 EXPECT_GT(out_analog_level, 100);
1221}
1222
1223TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001224 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001225 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1226 }
1227}
1228
niklase@google.com470e71d2011-07-07 08:21:25 +00001229TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001230 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001231 AudioProcessing::Config apm_config;
1232 apm_config.high_pass_filter.enabled = true;
1233 apm_->ApplyConfig(apm_config);
1234 apm_config.high_pass_filter.enabled = false;
1235 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001236}
1237
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001238TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001239 AudioProcessing::Config config = apm_->GetConfig();
1240 EXPECT_FALSE(config.echo_canceller.enabled);
1241 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001242 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001243 EXPECT_FALSE(config.noise_suppression.enabled);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001244 EXPECT_FALSE(config.voice_detection.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001245}
1246
1247TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001248 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001249 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001250 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001251 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001252 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001253 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001254 EXPECT_EQ(apm_->kNoError,
1255 apm_->ProcessStream(
1256 frame_.data.data(),
1257 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1258 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001259 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001260 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001261 EXPECT_EQ(apm_->kNoError,
1262 apm_->ProcessReverseStream(
1263 frame_.data.data(),
1264 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1265 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1266 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001267 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001268 }
1269 }
1270}
1271
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001272TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1273 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001274 const size_t kSamples = 160;
1275 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001276 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001277 float dest[kSamples] = {};
1278
1279 auto src_channels = &src[0];
1280 auto dest_channels = &dest[0];
1281
Niels Möller4f776ac2021-07-02 11:30:54 +02001282 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001283 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1284 StreamConfig(sample_rate, 1),
1285 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001286
1287 for (size_t i = 0; i < kSamples; ++i) {
1288 EXPECT_EQ(src[i], dest[i]);
1289 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001290
1291 // Same for ProcessReverseStream.
1292 float rev_dest[kSamples] = {};
1293 auto rev_dest_channels = &rev_dest[0];
1294
1295 StreamConfig input_stream = {sample_rate, 1};
1296 StreamConfig output_stream = {sample_rate, 1};
1297 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1298 output_stream, &rev_dest_channels));
1299
1300 for (size_t i = 0; i < kSamples; ++i) {
1301 EXPECT_EQ(src[i], rev_dest[i]);
1302 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001303}
1304
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001305TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1306 EnableAllComponents();
1307
pkasting25702cb2016-01-08 13:50:27 -08001308 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001309 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1310 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001311 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001312 ASSERT_EQ(0, feof(far_file_));
1313 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001314 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001315 CopyLeftToRightChannel(revframe_.data.data(),
1316 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001317
Per Åhgren2507f8c2020-03-19 12:33:29 +01001318 ASSERT_EQ(
1319 kNoErr,
1320 apm_->ProcessReverseStream(
1321 revframe_.data.data(),
1322 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1323 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1324 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001325
Per Åhgren2507f8c2020-03-19 12:33:29 +01001326 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001327
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001328 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001329 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001330 ASSERT_EQ(kNoErr,
1331 apm_->ProcessStream(
1332 frame_.data.data(),
1333 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1334 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001335 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001336 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001337
Per Åhgren2507f8c2020-03-19 12:33:29 +01001338 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001339 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001340 rewind(far_file_);
1341 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001342 }
1343}
1344
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001345TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001346 // Verify the filter is not active through undistorted audio when:
1347 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001348 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001349 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001350 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001351 EXPECT_EQ(apm_->kNoError,
1352 apm_->ProcessStream(
1353 frame_.data.data(),
1354 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1355 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001356 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001357 EXPECT_EQ(apm_->kNoError,
1358 apm_->ProcessStream(
1359 frame_.data.data(),
1360 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1361 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001362 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001363 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001364
1365 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001366 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001367 SetFrameTo(&frame_, 1000);
1368 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001369 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001370 EXPECT_EQ(apm_->kNoError,
1371 apm_->ProcessStream(
1372 frame_.data.data(),
1373 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1374 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001375 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001376 EXPECT_EQ(apm_->kNoError,
1377 apm_->ProcessStream(
1378 frame_.data.data(),
1379 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1380 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001381 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001382 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001383 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001384
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001385 // 3. Only GetStatistics-reporting VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001386 SetFrameTo(&frame_, 1000);
1387 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001388 apm_config.voice_detection.enabled = true;
1389 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001390 EXPECT_EQ(apm_->kNoError,
1391 apm_->ProcessStream(
1392 frame_.data.data(),
1393 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1394 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001395 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001396 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),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001401 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001402 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001403 apm_config.voice_detection.enabled = false;
1404 apm_->ApplyConfig(apm_config);
1405
Alessio Bazzica183c64c2021-10-19 13:32:02 +02001406 // 4. The VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001407 SetFrameTo(&frame_, 1000);
1408 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001409 apm_config.voice_detection.enabled = true;
1410 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001411 EXPECT_EQ(apm_->kNoError,
1412 apm_->ProcessStream(
1413 frame_.data.data(),
1414 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1415 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001416 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001417 EXPECT_EQ(apm_->kNoError,
1418 apm_->ProcessStream(
1419 frame_.data.data(),
1420 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1421 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001422 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001423 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001424 apm_config.voice_detection.enabled = false;
1425 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001426
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001427 // Check the test is valid. We should have distortion from the filter
1428 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001429 apm_config.echo_canceller.enabled = true;
1430 apm_config.echo_canceller.mobile_mode = false;
1431 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001432 frame_.samples_per_channel = 320;
1433 frame_.num_channels = 2;
1434 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001435 SetFrameTo(&frame_, 1000);
1436 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001437 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001438 EXPECT_EQ(apm_->kNoError,
1439 apm_->ProcessStream(
1440 frame_.data.data(),
1441 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1442 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001443 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001444 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001445}
1446
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001447#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1448void ApmTest::ProcessDebugDump(const std::string& in_filename,
1449 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001450 Format format,
1451 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001452 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001453 FILE* in_file = fopen(in_filename.c_str(), "rb");
1454 ASSERT_TRUE(in_file != NULL);
1455 audioproc::Event event_msg;
1456 bool first_init = true;
1457
1458 while (ReadMessageFromFile(in_file, &event_msg)) {
1459 if (event_msg.type() == audioproc::Event::INIT) {
1460 const audioproc::Init msg = event_msg.init();
1461 int reverse_sample_rate = msg.sample_rate();
1462 if (msg.has_reverse_sample_rate()) {
1463 reverse_sample_rate = msg.reverse_sample_rate();
1464 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001465 int output_sample_rate = msg.sample_rate();
1466 if (msg.has_output_sample_rate()) {
1467 output_sample_rate = msg.output_sample_rate();
1468 }
1469
Jonas Olssona4d87372019-07-05 19:08:33 +02001470 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1471 msg.num_input_channels(), msg.num_output_channels(),
1472 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001473 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001474 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001475 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001476 auto aec_dump =
1477 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1478 EXPECT_TRUE(aec_dump);
1479 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001480 first_init = false;
1481 }
1482
1483 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1484 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1485
1486 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001487 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001488 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001489 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001490 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1491 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001492 }
1493 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001494 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001495 if (format == kFloatFormat) {
1496 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001497 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001498 }
1499 }
1500 AnalyzeReverseStreamChooser(format);
1501
1502 } else if (event_msg.type() == audioproc::Event::STREAM) {
1503 const audioproc::Stream msg = event_msg.stream();
1504 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001505 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001506
Sam Zackrisson41478c72019-10-15 10:10:26 +02001507 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001508 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001509 if (msg.has_keypress()) {
1510 apm_->set_stream_key_pressed(msg.keypress());
1511 } else {
1512 apm_->set_stream_key_pressed(true);
1513 }
1514
1515 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001516 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001517 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001518 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001519 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1520 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001521 }
1522 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001523 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001524 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001525 if (format == kFloatFormat) {
1526 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001527 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001528 }
1529 }
1530 ProcessStreamChooser(format);
1531 }
1532 }
aleloif4dd1912017-06-15 01:55:38 -07001533 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001534 fclose(in_file);
1535}
1536
1537void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001538 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001539 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001540 std::string format_string;
1541 switch (format) {
1542 case kIntFormat:
1543 format_string = "_int";
1544 break;
1545 case kFloatFormat:
1546 format_string = "_float";
1547 break;
1548 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001549 const std::string ref_filename = test::TempFilename(
1550 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1551 const std::string out_filename = test::TempFilename(
1552 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001553 const std::string limited_filename = test::TempFilename(
1554 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1555 const size_t logging_limit_bytes = 100000;
1556 // We expect at least this many bytes in the created logfile.
1557 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001558 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001559 ProcessDebugDump(in_filename, ref_filename, format, -1);
1560 ProcessDebugDump(ref_filename, out_filename, format, -1);
1561 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001562
1563 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1564 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001565 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001566 ASSERT_TRUE(ref_file != NULL);
1567 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001568 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001569 std::unique_ptr<uint8_t[]> ref_bytes;
1570 std::unique_ptr<uint8_t[]> out_bytes;
1571 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001572
1573 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1574 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001575 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001576 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001577 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001578 while (ref_size > 0 && out_size > 0) {
1579 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001580 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001581 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001582 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001583 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001584 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001585 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1586 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001587 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001588 }
1589 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001590 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1591 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001592 EXPECT_NE(0, feof(ref_file));
1593 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001594 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001595 ASSERT_EQ(0, fclose(ref_file));
1596 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001597 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001598 remove(ref_filename.c_str());
1599 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001600 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001601}
1602
pbosc7a65692016-05-06 12:50:04 -07001603TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001604 VerifyDebugDumpTest(kIntFormat);
1605}
1606
pbosc7a65692016-05-06 12:50:04 -07001607TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001608 VerifyDebugDumpTest(kFloatFormat);
1609}
1610#endif
1611
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001612// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001613TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001614 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001615 const std::string filename =
1616 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001617 {
1618 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1619 EXPECT_FALSE(aec_dump);
1620 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001621
1622#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1623 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001624 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001625
aleloif4dd1912017-06-15 01:55:38 -07001626 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1627 EXPECT_TRUE(aec_dump);
1628 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001629 EXPECT_EQ(apm_->kNoError,
1630 apm_->ProcessStream(
1631 frame_.data.data(),
1632 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1633 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001634 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001635 EXPECT_EQ(apm_->kNoError,
1636 apm_->ProcessReverseStream(
1637 revframe_.data.data(),
1638 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1639 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1640 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001641 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001642
1643 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001644 FILE* fid = fopen(filename.c_str(), "r");
1645 ASSERT_TRUE(fid != NULL);
1646
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001647 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001648 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001649 ASSERT_EQ(0, remove(filename.c_str()));
1650#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001651 // Verify the file has NOT been written.
1652 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1653#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1654}
1655
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001656// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001657TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001658 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001659
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001660 const std::string filename =
1661 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001662 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1663 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001664
1665#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1666 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001667 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001668
Niels Möllere8e4dc42019-06-11 14:04:16 +02001669 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001670 EXPECT_TRUE(aec_dump);
1671 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001672 EXPECT_EQ(apm_->kNoError,
1673 apm_->ProcessReverseStream(
1674 revframe_.data.data(),
1675 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1676 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1677 revframe_.data.data()));
1678 EXPECT_EQ(apm_->kNoError,
1679 apm_->ProcessStream(
1680 frame_.data.data(),
1681 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1682 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001683 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001684 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001685
1686 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001687 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001688 ASSERT_TRUE(fid != NULL);
1689
1690 // Clean it up.
1691 ASSERT_EQ(0, fclose(fid));
1692 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001693#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1694}
1695
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001696// TODO(andrew): Add a test to process a few frames with different combinations
1697// of enabled components.
1698
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001699TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001700 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001701 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001702
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001703 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001704 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001705 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001706 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001707 for (size_t i = 0; i < arraysize(kChannels); i++) {
1708 for (size_t j = 0; j < arraysize(kChannels); j++) {
1709 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001710 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001711 test->set_num_reverse_channels(kChannels[i]);
1712 test->set_num_input_channels(kChannels[j]);
1713 test->set_num_output_channels(kChannels[j]);
1714 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001715 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001716 }
1717 }
1718 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001719#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1720 // To test the extended filter mode.
1721 audioproc::Test* test = ref_data.add_test();
1722 test->set_num_reverse_channels(2);
1723 test->set_num_input_channels(2);
1724 test->set_num_output_channels(2);
1725 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1726 test->set_use_aec_extended_filter(true);
1727#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001728 }
1729
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001730 for (int i = 0; i < ref_data.test_size(); i++) {
1731 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001732
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001733 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001734 // TODO(ajm): We no longer allow different input and output channels. Skip
1735 // these tests for now, but they should be removed from the set.
1736 if (test->num_input_channels() != test->num_output_channels())
1737 continue;
1738
Niels Möller4f776ac2021-07-02 11:30:54 +02001739 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001740 AudioProcessing::Config apm_config = apm_->GetConfig();
1741 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1742 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001743
1744 EnableAllComponents();
1745
Jonas Olssona4d87372019-07-05 19:08:33 +02001746 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001747 static_cast<size_t>(test->num_input_channels()),
1748 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001749 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001750
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001751 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001752 int has_voice_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001753 int analog_level = 127;
1754 int analog_level_average = 0;
1755 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001756#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001757 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001758#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001759
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001760 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001761 EXPECT_EQ(
1762 apm_->kNoError,
1763 apm_->ProcessReverseStream(
1764 revframe_.data.data(),
1765 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1766 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1767 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001768
1769 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001770 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001771
Per Åhgren2507f8c2020-03-19 12:33:29 +01001772 EXPECT_EQ(apm_->kNoError,
1773 apm_->ProcessStream(
1774 frame_.data.data(),
1775 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1776 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001777 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001778
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001779 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001780 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001781 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001782
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001783 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001784
Sam Zackrisson41478c72019-10-15 10:10:26 +02001785 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001786 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001787 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001788 EXPECT_TRUE(stats.voice_detected);
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001789 has_voice_count += *stats.voice_detected ? 1 : 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001790
Per Åhgren2507f8c2020-03-19 12:33:29 +01001791 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001792 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001793 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001794 ASSERT_EQ(frame_size, write_count);
1795
1796 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001797 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001798 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001799
1800#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1801 const int kStatsAggregationFrameNum = 100; // 1 second.
1802 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001803 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001804 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001805
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001806 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001807 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001808 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001809 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001810 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001811 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001812 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001813 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001814
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001815 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001816 const audioproc::Test::EchoMetrics& reference =
1817 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001818 constexpr float kEpsilon = 0.01;
1819 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1820 EXPECT_NEAR(echo_return_loss_enhancement,
1821 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001822 EXPECT_NEAR(residual_echo_likelihood,
1823 reference.residual_echo_likelihood(), kEpsilon);
1824 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1825 reference.residual_echo_likelihood_recent_max(),
1826 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001827 ++stats_index;
1828 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001829 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1830 message_echo->set_echo_return_loss(echo_return_loss);
1831 message_echo->set_echo_return_loss_enhancement(
1832 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001833 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1834 message_echo->set_residual_echo_likelihood_recent_max(
1835 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001836 }
1837 }
1838#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001839 }
1840 max_output_average /= frame_count;
1841 analog_level_average /= frame_count;
1842
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001843 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001844 const int kIntNear = 1;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001845 // When running the test on a N7 we get a {2, 6} difference of
Artem Titov0b489302021-07-28 20:50:03 +02001846 // `has_voice_count` and `max_output_average` is up to 18 higher.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001847 // All numbers being consistently higher on N7 compare to ref_data.
1848 // TODO(bjornv): If we start getting more of these offsets on Android we
1849 // should consider a different approach. Either using one slack for all,
1850 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001851#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001852 const int kHasVoiceCountOffset = 3;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001853 const int kHasVoiceCountNear = 8;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001854 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001855 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001856#else
1857 const int kHasVoiceCountOffset = 0;
1858 const int kHasVoiceCountNear = kIntNear;
1859 const int kMaxOutputAverageOffset = 0;
1860 const int kMaxOutputAverageNear = kIntNear;
1861#endif
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001862 EXPECT_NEAR(test->has_voice_count(),
Jonas Olssona4d87372019-07-05 19:08:33 +02001863 has_voice_count - kHasVoiceCountOffset, kHasVoiceCountNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001864
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001865 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001866 EXPECT_NEAR(test->max_output_average(),
1867 max_output_average - kMaxOutputAverageOffset,
1868 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001869 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001870 test->set_has_voice_count(has_voice_count);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001871
1872 test->set_analog_level_average(analog_level_average);
1873 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001874 }
1875
1876 rewind(far_file_);
1877 rewind(near_file_);
1878 }
1879
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001880 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001881 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001882 }
1883}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001884
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001885TEST_F(ApmTest, NoErrorsWithKeyboardChannel) {
1886 struct ChannelFormat {
1887 AudioProcessing::ChannelLayout in_layout;
1888 AudioProcessing::ChannelLayout out_layout;
1889 };
1890 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02001891 {AudioProcessing::kMonoAndKeyboard, AudioProcessing::kMono},
1892 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kMono},
1893 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kStereo},
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001894 };
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001895
Niels Möller4f776ac2021-07-02 11:30:54 +02001896 rtc::scoped_refptr<AudioProcessing> ap =
1897 AudioProcessingBuilderForTesting().Create();
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001898 // Enable one component just to ensure some processing takes place.
saza0bad15f2019-10-16 11:46:11 +02001899 AudioProcessing::Config config;
1900 config.noise_suppression.enabled = true;
1901 ap->ApplyConfig(config);
pkasting25702cb2016-01-08 13:50:27 -08001902 for (size_t i = 0; i < arraysize(cf); ++i) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001903 const int in_rate = 44100;
1904 const int out_rate = 48000;
1905 ChannelBuffer<float> in_cb(SamplesFromRate(in_rate),
1906 TotalChannelsFromLayout(cf[i].in_layout));
1907 ChannelBuffer<float> out_cb(SamplesFromRate(out_rate),
1908 ChannelsFromLayout(cf[i].out_layout));
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001909 bool has_keyboard = cf[i].in_layout == AudioProcessing::kMonoAndKeyboard ||
1910 cf[i].in_layout == AudioProcessing::kStereoAndKeyboard;
1911 StreamConfig in_sc(in_rate, ChannelsFromLayout(cf[i].in_layout),
1912 has_keyboard);
1913 StreamConfig out_sc(out_rate, ChannelsFromLayout(cf[i].out_layout));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001914
1915 // Run over a few chunks.
1916 for (int j = 0; j < 10; ++j) {
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001917 EXPECT_NOERR(ap->ProcessStream(in_cb.channels(), in_sc, out_sc,
1918 out_cb.channels()));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001919 }
1920 }
1921}
1922
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001923// Compares the reference and test arrays over a region around the expected
1924// delay. Finds the highest SNR in that region and adds the variance and squared
1925// error results to the supplied accumulators.
1926void UpdateBestSNR(const float* ref,
1927 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001928 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001929 int expected_delay,
1930 double* variance_acc,
1931 double* sq_error_acc) {
1932 double best_snr = std::numeric_limits<double>::min();
1933 double best_variance = 0;
1934 double best_sq_error = 0;
1935 // Search over a region of eight samples around the expected delay.
1936 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1937 ++delay) {
1938 double sq_error = 0;
1939 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001940 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001941 double error = test[i + delay] - ref[i];
1942 sq_error += error * error;
1943 variance += ref[i] * ref[i];
1944 }
1945
1946 if (sq_error == 0) {
1947 *variance_acc += variance;
1948 return;
1949 }
1950 double snr = variance / sq_error;
1951 if (snr > best_snr) {
1952 best_snr = snr;
1953 best_variance = variance;
1954 best_sq_error = sq_error;
1955 }
1956 }
1957
1958 *variance_acc += best_variance;
1959 *sq_error_acc += best_sq_error;
1960}
1961
1962// Used to test a multitude of sample rate and channel combinations. It works
1963// by first producing a set of reference files (in SetUpTestCase) that are
1964// assumed to be correct, as the used parameters are verified by other tests
1965// in this collection. Primarily the reference files are all produced at
1966// "native" rates which do not involve any resampling.
1967
1968// Each test pass produces an output file with a particular format. The output
1969// is matched against the reference file closest to its internal processing
1970// format. If necessary the output is resampled back to its process format.
1971// Due to the resampling distortion, we don't expect identical results, but
1972// enforce SNR thresholds which vary depending on the format. 0 is a special
1973// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001974typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001975class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001976 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001977 public:
1978 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001979 : input_rate_(std::get<0>(GetParam())),
1980 output_rate_(std::get<1>(GetParam())),
1981 reverse_input_rate_(std::get<2>(GetParam())),
1982 reverse_output_rate_(std::get<3>(GetParam())),
1983 expected_snr_(std::get<4>(GetParam())),
1984 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001985
1986 virtual ~AudioProcessingTest() {}
1987
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001988 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001989 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07001990 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08001991 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08001992 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
1993 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1994 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001995 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07001996 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
1997 kNativeRates[i], kNumChannels[j], kNumChannels[j],
1998 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001999 }
2000 }
2001 }
2002 }
2003
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02002004 void TearDown() {
2005 // Remove "out" files after each test.
2006 ClearTempOutFiles();
2007 }
2008
Mirko Bonadei71061bc2019-06-04 09:01:51 +02002009 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07002010
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002011 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02002012 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07002013 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002014 static void ProcessFormat(int input_rate,
2015 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07002016 int reverse_input_rate,
2017 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08002018 size_t num_input_channels,
2019 size_t num_output_channels,
2020 size_t num_reverse_input_channels,
2021 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02002022 const std::string& output_file_prefix) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002023 rtc::scoped_refptr<AudioProcessing> ap =
2024 AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01002025 AudioProcessing::Config apm_config = ap->GetConfig();
2026 apm_config.gain_controller1.analog_gain_controller.enabled = false;
2027 ap->ApplyConfig(apm_config);
2028
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002029 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002030
ekmeyerson60d9b332015-08-14 10:35:55 -07002031 ProcessingConfig processing_config = {
2032 {{input_rate, num_input_channels},
2033 {output_rate, num_output_channels},
2034 {reverse_input_rate, num_reverse_input_channels},
2035 {reverse_output_rate, num_reverse_output_channels}}};
2036 ap->Initialize(processing_config);
2037
2038 FILE* far_file =
2039 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002040 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02002041 FILE* out_file = fopen(
2042 OutputFilePath(
2043 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2044 reverse_output_rate, num_input_channels, num_output_channels,
2045 num_reverse_input_channels, num_reverse_output_channels, kForward)
2046 .c_str(),
2047 "wb");
2048 FILE* rev_out_file = fopen(
2049 OutputFilePath(
2050 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2051 reverse_output_rate, num_input_channels, num_output_channels,
2052 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2053 .c_str(),
2054 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002055 ASSERT_TRUE(far_file != NULL);
2056 ASSERT_TRUE(near_file != NULL);
2057 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002058 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002059
2060 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
2061 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002062 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
2063 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002064 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
2065 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002066 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
2067 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002068
2069 // Temporary buffers.
2070 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002071 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2072 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08002073 std::unique_ptr<float[]> float_data(new float[max_length]);
2074 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002075
2076 int analog_level = 127;
2077 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2078 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002079 EXPECT_NOERR(ap->ProcessReverseStream(
2080 rev_cb.channels(), processing_config.reverse_input_stream(),
2081 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002082
2083 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002084 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002085
2086 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002087 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2088 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002089
ekmeyerson60d9b332015-08-14 10:35:55 -07002090 // Dump forward output to file.
2091 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002092 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002093 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002094
Jonas Olssona4d87372019-07-05 19:08:33 +02002095 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2096 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002097
ekmeyerson60d9b332015-08-14 10:35:55 -07002098 // Dump reverse output to file.
2099 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2100 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002101 size_t rev_out_length =
2102 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002103
Jonas Olssona4d87372019-07-05 19:08:33 +02002104 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2105 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002106
Sam Zackrisson41478c72019-10-15 10:10:26 +02002107 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002108 }
2109 fclose(far_file);
2110 fclose(near_file);
2111 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002112 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002113 }
2114
2115 protected:
2116 int input_rate_;
2117 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002118 int reverse_input_rate_;
2119 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002120 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002121 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002122};
2123
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002124TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002125 struct ChannelFormat {
2126 int num_input;
2127 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002128 int num_reverse_input;
2129 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002130 };
2131 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002132 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2133 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002134 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002135
pkasting25702cb2016-01-08 13:50:27 -08002136 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002137 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2138 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2139 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002140
ekmeyerson60d9b332015-08-14 10:35:55 -07002141 // Verify output for both directions.
2142 std::vector<StreamDirection> stream_directions;
2143 stream_directions.push_back(kForward);
2144 stream_directions.push_back(kReverse);
2145 for (StreamDirection file_direction : stream_directions) {
2146 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2147 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2148 const int out_num =
2149 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2150 const double expected_snr =
2151 file_direction ? expected_reverse_snr_ : expected_snr_;
2152
2153 const int min_ref_rate = std::min(in_rate, out_rate);
2154 int ref_rate;
2155
2156 if (min_ref_rate > 32000) {
2157 ref_rate = 48000;
2158 } else if (min_ref_rate > 16000) {
2159 ref_rate = 32000;
2160 } else if (min_ref_rate > 8000) {
2161 ref_rate = 16000;
2162 } else {
2163 ref_rate = 8000;
2164 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002165
ekmeyerson60d9b332015-08-14 10:35:55 -07002166 FILE* out_file = fopen(
2167 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2168 reverse_output_rate_, cf[i].num_input,
2169 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002170 cf[i].num_reverse_output, file_direction)
2171 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002172 "rb");
2173 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002174 FILE* ref_file =
2175 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2176 cf[i].num_output, cf[i].num_output,
2177 cf[i].num_reverse_output,
2178 cf[i].num_reverse_output, file_direction)
2179 .c_str(),
2180 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002181 ASSERT_TRUE(out_file != NULL);
2182 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002183
pkasting25702cb2016-01-08 13:50:27 -08002184 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2185 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002186 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002187 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002188 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002189 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002190 // Data from the resampled output, in case the reference and output rates
2191 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002192 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002193
ekmeyerson60d9b332015-08-14 10:35:55 -07002194 PushResampler<float> resampler;
2195 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002196
ekmeyerson60d9b332015-08-14 10:35:55 -07002197 // Compute the resampling delay of the output relative to the reference,
2198 // to find the region over which we should search for the best SNR.
2199 float expected_delay_sec = 0;
2200 if (in_rate != ref_rate) {
2201 // Input resampling delay.
2202 expected_delay_sec +=
2203 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2204 }
2205 if (out_rate != ref_rate) {
2206 // Output resampling delay.
2207 expected_delay_sec +=
2208 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2209 // Delay of converting the output back to its processing rate for
2210 // testing.
2211 expected_delay_sec +=
2212 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2213 }
2214 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002215 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002216
ekmeyerson60d9b332015-08-14 10:35:55 -07002217 double variance = 0;
2218 double sq_error = 0;
2219 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2220 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2221 float* out_ptr = out_data.get();
2222 if (out_rate != ref_rate) {
2223 // Resample the output back to its internal processing rate if
2224 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002225 ASSERT_EQ(ref_length,
2226 static_cast<size_t>(resampler.Resample(
2227 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002228 out_ptr = cmp_data.get();
2229 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002230
Artem Titov0b489302021-07-28 20:50:03 +02002231 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002232 // SNR of reference vs output.
2233 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2234 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002235 }
2236
ekmeyerson60d9b332015-08-14 10:35:55 -07002237 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2238 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2239 << cf[i].num_input << ", " << cf[i].num_output << ", "
2240 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2241 << ", " << file_direction << "): ";
2242 if (sq_error > 0) {
2243 double snr = 10 * log10(variance / sq_error);
2244 EXPECT_GE(snr, expected_snr);
2245 EXPECT_NE(0, expected_snr);
2246 std::cout << "SNR=" << snr << " dB" << std::endl;
2247 } else {
aluebs776593b2016-03-15 14:04:58 -07002248 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002249 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002250
ekmeyerson60d9b332015-08-14 10:35:55 -07002251 fclose(out_file);
2252 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002253 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002254 }
2255}
2256
2257#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002258INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002259 CommonFormats,
2260 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002261 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2262 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2263 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2264 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2265 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2266 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2267 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2268 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2269 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2270 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2271 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2272 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002273
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002274 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2275 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2276 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2277 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2278 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2279 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2280 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2281 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2282 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2283 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2284 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2285 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002286
Per Åhgrenc0424252019-12-10 13:04:15 +01002287 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2288 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2289 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002290 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2291 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2292 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2293 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2294 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002295 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002296 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2297 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2298 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002299
Per Åhgrenc0424252019-12-10 13:04:15 +01002300 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2301 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2302 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002303 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2304 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2305 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2306 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2307 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2308 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2309 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002310 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002311 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002312
2313#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002314INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002315 CommonFormats,
2316 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002317 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2318 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2319 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002320 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2321 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2322 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002323 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2324 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2325 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002326 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2327 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2328 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002329
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002330 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2331 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2332 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2333 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2334 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2335 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002336 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2337 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2338 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2339 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2340 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2341 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002342
Per Åhgrenc0424252019-12-10 13:04:15 +01002343 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2344 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2345 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002346 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2347 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2348 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002349 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002350 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002351 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002352 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2353 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2354 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002355
Per Åhgrenc0424252019-12-10 13:04:15 +01002356 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2357 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2358 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002359 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2360 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2361 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002362 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002363 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002364 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002365 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2366 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002367 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002368#endif
2369
Per Åhgren3e8bf282019-08-29 23:38:40 +02002370// Produces a scoped trace debug output.
2371std::string ProduceDebugText(int render_input_sample_rate_hz,
2372 int render_output_sample_rate_hz,
2373 int capture_input_sample_rate_hz,
2374 int capture_output_sample_rate_hz,
2375 size_t render_input_num_channels,
2376 size_t render_output_num_channels,
2377 size_t capture_input_num_channels,
2378 size_t capture_output_num_channels) {
2379 rtc::StringBuilder ss;
2380 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002381 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002382 << render_input_sample_rate_hz
2383 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002384 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002385 << render_output_sample_rate_hz
2386 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002387 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002388 << capture_input_sample_rate_hz
2389 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002390 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002391 << capture_output_sample_rate_hz
2392 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002393 "\nNumber of channels:"
2394 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002395 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002396 << "\n Render output: " << render_output_num_channels
2397 << "\n Capture input: " << capture_input_num_channels
2398 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002399 return ss.Release();
2400}
2401
2402// Validates that running the audio processing module using various combinations
2403// of sample rates and number of channels works as intended.
2404void RunApmRateAndChannelTest(
2405 rtc::ArrayView<const int> sample_rates_hz,
2406 rtc::ArrayView<const int> render_channel_counts,
2407 rtc::ArrayView<const int> capture_channel_counts) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002408 rtc::scoped_refptr<AudioProcessing> apm =
2409 AudioProcessingBuilderForTesting().Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002410 webrtc::AudioProcessing::Config apm_config;
2411 apm_config.echo_canceller.enabled = true;
2412 apm->ApplyConfig(apm_config);
2413
2414 StreamConfig render_input_stream_config;
2415 StreamConfig render_output_stream_config;
2416 StreamConfig capture_input_stream_config;
2417 StreamConfig capture_output_stream_config;
2418
2419 std::vector<float> render_input_frame_channels;
2420 std::vector<float*> render_input_frame;
2421 std::vector<float> render_output_frame_channels;
2422 std::vector<float*> render_output_frame;
2423 std::vector<float> capture_input_frame_channels;
2424 std::vector<float*> capture_input_frame;
2425 std::vector<float> capture_output_frame_channels;
2426 std::vector<float*> capture_output_frame;
2427
2428 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2429 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2430 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2431 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2432 for (size_t render_input_num_channels : render_channel_counts) {
2433 for (size_t capture_input_num_channels : capture_channel_counts) {
2434 size_t render_output_num_channels = render_input_num_channels;
2435 size_t capture_output_num_channels = capture_input_num_channels;
2436 auto populate_audio_frame = [](int sample_rate_hz,
2437 size_t num_channels,
2438 StreamConfig* cfg,
2439 std::vector<float>* channels_data,
2440 std::vector<float*>* frame_data) {
2441 cfg->set_sample_rate_hz(sample_rate_hz);
2442 cfg->set_num_channels(num_channels);
2443 cfg->set_has_keyboard(false);
2444
2445 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2446 channels_data->resize(num_channels * max_frame_size);
2447 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2448 frame_data->resize(num_channels);
2449 for (size_t channel = 0; channel < num_channels; ++channel) {
2450 (*frame_data)[channel] =
2451 &(*channels_data)[channel * max_frame_size];
2452 }
2453 };
2454
2455 populate_audio_frame(
2456 render_input_sample_rate_hz, render_input_num_channels,
2457 &render_input_stream_config, &render_input_frame_channels,
2458 &render_input_frame);
2459 populate_audio_frame(
2460 render_output_sample_rate_hz, render_output_num_channels,
2461 &render_output_stream_config, &render_output_frame_channels,
2462 &render_output_frame);
2463 populate_audio_frame(
2464 capture_input_sample_rate_hz, capture_input_num_channels,
2465 &capture_input_stream_config, &capture_input_frame_channels,
2466 &capture_input_frame);
2467 populate_audio_frame(
2468 capture_output_sample_rate_hz, capture_output_num_channels,
2469 &capture_output_stream_config, &capture_output_frame_channels,
2470 &capture_output_frame);
2471
2472 for (size_t frame = 0; frame < 2; ++frame) {
2473 SCOPED_TRACE(ProduceDebugText(
2474 render_input_sample_rate_hz, render_output_sample_rate_hz,
2475 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2476 render_input_num_channels, render_output_num_channels,
2477 render_input_num_channels, capture_output_num_channels));
2478
2479 int result = apm->ProcessReverseStream(
2480 &render_input_frame[0], render_input_stream_config,
2481 render_output_stream_config, &render_output_frame[0]);
2482 EXPECT_EQ(result, AudioProcessing::kNoError);
2483 result = apm->ProcessStream(
2484 &capture_input_frame[0], capture_input_stream_config,
2485 capture_output_stream_config, &capture_output_frame[0]);
2486 EXPECT_EQ(result, AudioProcessing::kNoError);
2487 }
2488 }
2489 }
2490 }
2491 }
2492 }
2493 }
2494}
2495
Alessio Bazzica3438a932020-10-14 12:47:50 +02002496constexpr void Toggle(bool& b) {
2497 b ^= true;
2498}
2499
niklase@google.com470e71d2011-07-07 08:21:25 +00002500} // namespace
peahc19f3122016-10-07 14:54:10 -07002501
Alessio Bazzicac054e782018-04-16 12:10:09 +02002502TEST(RuntimeSettingTest, TestDefaultCtor) {
2503 auto s = AudioProcessing::RuntimeSetting();
2504 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2505}
2506
Alessio Bazzicac054e782018-04-16 12:10:09 +02002507TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2508 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2509 auto s = AudioProcessing::RuntimeSetting();
2510 ASSERT_TRUE(q.Insert(&s));
2511 ASSERT_TRUE(q.Remove(&s));
2512 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2513}
2514
Sam Zackrisson0beac582017-09-25 12:04:02 +02002515TEST(ApmConfiguration, EnablePostProcessing) {
2516 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002517 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002518 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002519 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002520 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002521 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002522 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002523 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002524 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002525
Per Åhgren2507f8c2020-03-19 12:33:29 +01002526 Int16FrameData audio;
2527 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002528 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2529
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002530 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002531 apm->ProcessStream(audio.data.data(),
2532 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2533 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002534 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002535}
2536
Alex Loiko5825aa62017-12-18 16:02:40 +01002537TEST(ApmConfiguration, EnablePreProcessing) {
2538 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002539 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002540 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002541 auto mock_pre_processor =
2542 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002543 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002544 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002545 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002546 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002547
Per Åhgren2507f8c2020-03-19 12:33:29 +01002548 Int16FrameData audio;
2549 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002550 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2551
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002552 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002553 apm->ProcessReverseStream(
2554 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2555 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2556 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002557}
2558
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002559TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2560 // Verify that apm uses a capture analyzer if one is provided.
2561 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002562 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002563 auto mock_capture_analyzer =
2564 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2565 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002566 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002567 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2568 .Create();
2569
Per Åhgren2507f8c2020-03-19 12:33:29 +01002570 Int16FrameData audio;
2571 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002572 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2573
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002574 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002575 apm->ProcessStream(audio.data.data(),
2576 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2577 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002578 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002579}
2580
Alex Loiko73ec0192018-05-15 10:52:28 +02002581TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2582 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002583 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002584 auto mock_pre_processor =
2585 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2586 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002587 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002588 .SetRenderPreProcessing(std::move(mock_pre_processor))
2589 .Create();
2590 apm->SetRuntimeSetting(
2591 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2592
2593 // RuntimeSettings forwarded during 'Process*Stream' calls.
2594 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002595 Int16FrameData audio;
2596 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002597 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2598
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002599 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2600 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002601 apm->ProcessReverseStream(
2602 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2603 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2604 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002605}
2606
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002607class MyEchoControlFactory : public EchoControlFactory {
2608 public:
2609 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2610 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002611 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2612 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002613 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2614 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002615 return std::unique_ptr<EchoControl>(ec);
2616 }
Per Åhgrence202a02019-09-02 17:01:19 +02002617
2618 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002619 int num_render_channels,
2620 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002621 return Create(sample_rate_hz);
2622 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002623};
2624
2625TEST(ApmConfiguration, EchoControlInjection) {
2626 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002627 std::unique_ptr<EchoControlFactory> echo_control_factory(
2628 new MyEchoControlFactory());
2629
Alex Loiko5825aa62017-12-18 16:02:40 +01002630 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002631 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002632 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002633 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002634
Per Åhgren2507f8c2020-03-19 12:33:29 +01002635 Int16FrameData audio;
2636 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002637 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002638 apm->ProcessStream(audio.data.data(),
2639 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2640 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002641 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002642 apm->ProcessReverseStream(
2643 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2644 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2645 audio.data.data());
2646 apm->ProcessStream(audio.data.data(),
2647 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2648 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002649 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002650}
Ivo Creusenae026092017-11-20 13:07:16 +01002651
Niels Möller4f776ac2021-07-02 11:30:54 +02002652rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002653 rtc::scoped_refptr<AudioProcessing> apm =
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002654 AudioProcessingBuilderForTesting().Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002655 if (!apm) {
2656 return apm;
2657 }
2658
2659 ProcessingConfig processing_config = {
2660 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2661
2662 if (apm->Initialize(processing_config) != 0) {
2663 return nullptr;
2664 }
2665
2666 // Disable all components except for an AEC and the residual echo detector.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002667 AudioProcessing::Config apm_config;
2668 apm_config.residual_echo_detector.enabled = true;
2669 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002670 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002671 apm_config.gain_controller2.enabled = false;
2672 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002673 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002674 apm_config.noise_suppression.enabled = false;
saza0bad15f2019-10-16 11:46:11 +02002675 apm_config.voice_detection.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002676 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002677 return apm;
2678}
2679
2680#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2681#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2682#else
2683#define MAYBE_ApmStatistics ApmStatistics
2684#endif
2685
Per Åhgren8607f842019-04-12 22:02:26 +02002686TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2687 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002688 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002689 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002690 AudioProcessing::Config apm_config;
2691 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002692 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002693
2694 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002695 Int16FrameData frame;
2696 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002697 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002698
2699 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002700 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002701 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2702 ptr[i] = 10000 * ((i % 3) - 1);
2703 }
2704
2705 // Do some processing.
2706 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002707 EXPECT_EQ(apm->ProcessReverseStream(
2708 frame.data.data(),
2709 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2710 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2711 frame.data.data()),
2712 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002713 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002714 EXPECT_EQ(apm->ProcessStream(
2715 frame.data.data(),
2716 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2717 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002718 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002719 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002720 }
2721
2722 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002723 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002724 // We expect all statistics to be set and have a sensible value.
2725 ASSERT_TRUE(stats.residual_echo_likelihood);
2726 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2727 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2728 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max);
2729 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2730 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2731 ASSERT_TRUE(stats.echo_return_loss);
2732 EXPECT_NE(*stats.echo_return_loss, -100.0);
2733 ASSERT_TRUE(stats.echo_return_loss_enhancement);
2734 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002735}
2736
2737TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2738 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002739 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002740 ASSERT_TRUE(apm);
2741
2742 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002743 Int16FrameData frame;
2744 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002745 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002746
2747 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002748 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002749 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2750 ptr[i] = 10000 * ((i % 3) - 1);
2751 }
2752
2753 // Do some processing.
2754 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002755 EXPECT_EQ(apm->ProcessReverseStream(
2756 frame.data.data(),
2757 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2758 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2759 frame.data.data()),
2760 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002761 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002762 EXPECT_EQ(apm->ProcessStream(
2763 frame.data.data(),
2764 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2765 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002766 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002767 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002768 }
2769
2770 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002771 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002772 // We expect only the residual echo detector statistics to be set and have a
2773 // sensible value.
2774 EXPECT_TRUE(stats.residual_echo_likelihood);
2775 if (stats.residual_echo_likelihood) {
2776 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2777 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2778 }
2779 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max);
2780 if (stats.residual_echo_likelihood_recent_max) {
2781 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2782 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2783 }
2784 EXPECT_FALSE(stats.echo_return_loss);
2785 EXPECT_FALSE(stats.echo_return_loss_enhancement);
Ivo Creusenae026092017-11-20 13:07:16 +01002786}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002787
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002788TEST(ApmStatistics, ReportHasVoice) {
2789 ProcessingConfig processing_config = {
2790 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2791 AudioProcessing::Config config;
2792
2793 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002794 Int16FrameData frame;
2795 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002796 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2797
2798 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002799 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002800 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2801 ptr[i] = 10000 * ((i % 3) - 1);
2802 }
2803
Niels Möller4f776ac2021-07-02 11:30:54 +02002804 rtc::scoped_refptr<AudioProcessing> apm =
2805 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002806 apm->Initialize(processing_config);
2807
2808 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002809 EXPECT_EQ(
2810 apm->ProcessStream(frame.data.data(),
2811 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2812 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002813 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002814 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002815 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002816
2817 // If enabled, metrics should be reported.
2818 config.voice_detection.enabled = true;
2819 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002820 EXPECT_EQ(
2821 apm->ProcessStream(frame.data.data(),
2822 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2823 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002824 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002825 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002826 auto stats = apm->GetStatistics();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002827 EXPECT_TRUE(stats.voice_detected);
2828
2829 // If re-disabled, the value is again not reported.
2830 config.voice_detection.enabled = false;
2831 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002832 EXPECT_EQ(
2833 apm->ProcessStream(frame.data.data(),
2834 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2835 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002836 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002837 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002838 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002839}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002840
2841TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2842 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2843 std::array<int, 2> render_channel_counts = {1, 7};
2844 std::array<int, 2> capture_channel_counts = {1, 7};
2845 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2846 capture_channel_counts);
2847}
2848
2849TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2850 std::array<int, 1> sample_rates_hz = {48000};
2851 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2852 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2853 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2854 capture_channel_counts);
2855}
2856
2857TEST(ApmConfiguration, HandlingOfRateCombinations) {
2858 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2859 48000, 96000, 192000, 384000};
2860 std::array<int, 1> render_channel_counts = {2};
2861 std::array<int, 1> capture_channel_counts = {2};
2862 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2863 capture_channel_counts);
2864}
2865
Yves Gerey1fce3f82019-12-05 17:45:31 +01002866TEST(ApmConfiguration, SelfAssignment) {
2867 // At some point memory sanitizer was complaining about self-assigment.
2868 // Make sure we don't regress.
2869 AudioProcessing::Config config;
2870 AudioProcessing::Config* config2 = &config;
2871 *config2 = *config2; // Workaround -Wself-assign-overloaded
2872 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2873}
2874
Alessio Bazzica3438a932020-10-14 12:47:50 +02002875TEST(AudioProcessing, GainController1ConfigEqual) {
2876 AudioProcessing::Config::GainController1 a;
2877 AudioProcessing::Config::GainController1 b;
2878 EXPECT_EQ(a, b);
2879
2880 Toggle(a.enabled);
2881 b.enabled = a.enabled;
2882 EXPECT_EQ(a, b);
2883
2884 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2885 b.mode = a.mode;
2886 EXPECT_EQ(a, b);
2887
2888 a.target_level_dbfs++;
2889 b.target_level_dbfs = a.target_level_dbfs;
2890 EXPECT_EQ(a, b);
2891
2892 a.compression_gain_db++;
2893 b.compression_gain_db = a.compression_gain_db;
2894 EXPECT_EQ(a, b);
2895
2896 Toggle(a.enable_limiter);
2897 b.enable_limiter = a.enable_limiter;
2898 EXPECT_EQ(a, b);
2899
Alessio Bazzica3438a932020-10-14 12:47:50 +02002900 auto& a_analog = a.analog_gain_controller;
2901 auto& b_analog = b.analog_gain_controller;
2902
2903 Toggle(a_analog.enabled);
2904 b_analog.enabled = a_analog.enabled;
2905 EXPECT_EQ(a, b);
2906
2907 a_analog.startup_min_volume++;
2908 b_analog.startup_min_volume = a_analog.startup_min_volume;
2909 EXPECT_EQ(a, b);
2910
2911 a_analog.clipped_level_min++;
2912 b_analog.clipped_level_min = a_analog.clipped_level_min;
2913 EXPECT_EQ(a, b);
2914
Alessio Bazzica3438a932020-10-14 12:47:50 +02002915 Toggle(a_analog.enable_digital_adaptive);
2916 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2917 EXPECT_EQ(a, b);
2918}
2919
2920// Checks that one differing parameter is sufficient to make two configs
2921// different.
2922TEST(AudioProcessing, GainController1ConfigNotEqual) {
2923 AudioProcessing::Config::GainController1 a;
2924 const AudioProcessing::Config::GainController1 b;
2925
2926 Toggle(a.enabled);
2927 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002928 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002929
2930 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2931 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002932 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002933
2934 a.target_level_dbfs++;
2935 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002936 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002937
2938 a.compression_gain_db++;
2939 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002940 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002941
2942 Toggle(a.enable_limiter);
2943 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002944 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002945
Alessio Bazzica3438a932020-10-14 12:47:50 +02002946 auto& a_analog = a.analog_gain_controller;
2947 const auto& b_analog = b.analog_gain_controller;
2948
2949 Toggle(a_analog.enabled);
2950 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002951 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002952
2953 a_analog.startup_min_volume++;
2954 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002955 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002956
2957 a_analog.clipped_level_min++;
2958 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002959 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002960
Alessio Bazzica3438a932020-10-14 12:47:50 +02002961 Toggle(a_analog.enable_digital_adaptive);
2962 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002963 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002964}
2965
2966TEST(AudioProcessing, GainController2ConfigEqual) {
2967 AudioProcessing::Config::GainController2 a;
2968 AudioProcessing::Config::GainController2 b;
2969 EXPECT_EQ(a, b);
2970
2971 Toggle(a.enabled);
2972 b.enabled = a.enabled;
2973 EXPECT_EQ(a, b);
2974
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002975 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002976 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
2977 EXPECT_EQ(a, b);
2978
2979 auto& a_adaptive = a.adaptive_digital;
2980 auto& b_adaptive = b.adaptive_digital;
2981
2982 Toggle(a_adaptive.enabled);
2983 b_adaptive.enabled = a_adaptive.enabled;
2984 EXPECT_EQ(a, b);
2985
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002986 Toggle(a_adaptive.dry_run);
2987 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002988 EXPECT_EQ(a, b);
2989
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02002990 a_adaptive.headroom_db += 1.0f;
2991 b_adaptive.headroom_db = a_adaptive.headroom_db;
2992 EXPECT_EQ(a, b);
2993
2994 a_adaptive.max_gain_db += 1.0f;
2995 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
2996 EXPECT_EQ(a, b);
2997
2998 a_adaptive.initial_gain_db += 1.0f;
2999 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3000 EXPECT_EQ(a, b);
3001
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003002 a_adaptive.vad_reset_period_ms++;
3003 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003004 EXPECT_EQ(a, b);
3005
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003006 a_adaptive.adjacent_speech_frames_threshold++;
3007 b_adaptive.adjacent_speech_frames_threshold =
3008 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003009 EXPECT_EQ(a, b);
3010
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003011 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003012 b_adaptive.max_gain_change_db_per_second =
3013 a_adaptive.max_gain_change_db_per_second;
3014 EXPECT_EQ(a, b);
3015
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003016 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003017 b_adaptive.max_output_noise_level_dbfs =
3018 a_adaptive.max_output_noise_level_dbfs;
3019 EXPECT_EQ(a, b);
3020}
3021
3022// Checks that one differing parameter is sufficient to make two configs
3023// different.
3024TEST(AudioProcessing, GainController2ConfigNotEqual) {
3025 AudioProcessing::Config::GainController2 a;
3026 const AudioProcessing::Config::GainController2 b;
3027
3028 Toggle(a.enabled);
3029 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003030 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003031
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003032 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003033 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003034 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003035
3036 auto& a_adaptive = a.adaptive_digital;
3037 const auto& b_adaptive = b.adaptive_digital;
3038
3039 Toggle(a_adaptive.enabled);
3040 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003041 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003042
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003043 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003044 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003045 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003046
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003047 a_adaptive.headroom_db += 1.0f;
3048 EXPECT_NE(a, b);
3049 a_adaptive = b_adaptive;
3050
3051 a_adaptive.max_gain_db += 1.0f;
3052 EXPECT_NE(a, b);
3053 a_adaptive = b_adaptive;
3054
3055 a_adaptive.initial_gain_db += 1.0f;
3056 EXPECT_NE(a, b);
3057 a_adaptive = b_adaptive;
3058
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003059 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003060 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003061 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003062
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003063 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003064 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003065 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003066
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003067 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003068 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003069 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003070
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003071 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003072 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003073 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003074}
3075
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003076} // namespace webrtc