blob: 9109e299fb61f0d8e8ee5e5ceae99782d9eb277f [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 }
kwiberg9e2be5f2016-09-14 05:23:22 -0700108 RTC_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;
203 apm_config.gain_controller1.analog_level_minimum = 0;
204 apm_config.gain_controller1.analog_level_maximum = 255;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000205#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000206
saza0bad15f2019-10-16 11:46:11 +0200207 apm_config.noise_suppression.enabled = true;
208
peah8271d042016-11-22 07:24:52 -0800209 apm_config.high_pass_filter.enabled = true;
Sam Zackrisson0824c6f2019-10-07 14:03:56 +0200210 apm_config.voice_detection.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100211 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800212 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000213}
214
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000215// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000216template <class T>
217T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200218 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000219}
220
Per Åhgren2507f8c2020-03-19 12:33:29 +0100221int16_t MaxAudioFrame(const Int16FrameData& frame) {
222 const size_t length = frame.samples_per_channel * frame.num_channels;
223 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800224 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100225 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000226 }
227
228 return max_data;
229}
230
Alex Loiko890988c2017-08-31 10:25:48 +0200231void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700232 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000233 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000234 ASSERT_TRUE(file != NULL);
235
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100236 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000237 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800238 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000239 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000240
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000241 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000242 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200243 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000244 fclose(file);
245}
246
Alex Loiko890988c2017-08-31 10:25:48 +0200247std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200248 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000249 // Resource files are all stereo.
250 ss << name << sample_rate_hz / 1000 << "_stereo";
251 return test::ResourcePath(ss.str(), "pcm");
252}
253
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000254// Temporary filenames unique to this process. Used to be able to run these
255// tests in parallel as each process needs to be running in isolation they can't
256// have competing filenames.
257std::map<std::string, std::string> temp_filenames;
258
Alex Loiko890988c2017-08-31 10:25:48 +0200259std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000260 int input_rate,
261 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700262 int reverse_input_rate,
263 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800264 size_t num_input_channels,
265 size_t num_output_channels,
266 size_t num_reverse_input_channels,
267 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700268 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200269 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700270 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
271 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000272 if (num_output_channels == 1) {
273 ss << "mono";
274 } else if (num_output_channels == 2) {
275 ss << "stereo";
276 } else {
kwiberg9e2be5f2016-09-14 05:23:22 -0700277 RTC_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000278 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700279 ss << output_rate / 1000;
280 if (num_reverse_output_channels == 1) {
281 ss << "_rmono";
282 } else if (num_reverse_output_channels == 2) {
283 ss << "_rstereo";
284 } else {
kwiberg9e2be5f2016-09-14 05:23:22 -0700285 RTC_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700286 }
287 ss << reverse_output_rate / 1000;
288 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000289
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000290 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700291 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000292 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
293 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000294}
295
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000296void ClearTempFiles() {
297 for (auto& kv : temp_filenames)
298 remove(kv.second.c_str());
299}
300
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200301// Only remove "out" files. Keep "ref" files.
302void ClearTempOutFiles() {
303 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
304 const std::string& filename = it->first;
305 if (filename.substr(0, 3).compare("out") == 0) {
306 remove(it->second.c_str());
307 temp_filenames.erase(it++);
308 } else {
309 it++;
310 }
311 }
312}
313
Alex Loiko890988c2017-08-31 10:25:48 +0200314void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000315 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000316 ASSERT_TRUE(file != NULL);
317 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000318 fclose(file);
319}
320
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000321// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
322// stereo) file, converts to deinterleaved float (optionally downmixing) and
Artem Titov0b489302021-07-28 20:50:03 +0200323// returns the result in `cb`. Returns false if the file ended (or on error) and
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000324// true otherwise.
325//
Artem Titov0b489302021-07-28 20:50:03 +0200326// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000327// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200328bool ReadChunk(FILE* file,
329 int16_t* int_data,
330 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000331 ChannelBuffer<float>* cb) {
332 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000333 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000334 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
335 if (read_count != frame_size) {
336 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700337 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000338 return false; // This is expected.
339 }
340
341 S16ToFloat(int_data, frame_size, float_data);
342 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000343 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000344 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200345 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000346 }
347
348 return true;
349}
350
Per Åhgrena43178c2020-09-25 12:02:32 +0200351// Returns the reference file name that matches the current CPU
352// architecture/optimizations.
353std::string GetReferenceFilename() {
354#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
355 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
356#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
357 if (GetCPUInfo(kAVX2) != 0) {
358 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
359 }
360 return test::ResourcePath("audio_processing/output_data_float", "pb");
361#endif
362}
363
niklase@google.com470e71d2011-07-07 08:21:25 +0000364class ApmTest : public ::testing::Test {
365 protected:
366 ApmTest();
367 virtual void SetUp();
368 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000369
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200370 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000371
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200372 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000373
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000374 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200375 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000376
377 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000378 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000379 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800380 size_t num_input_channels,
381 size_t num_output_channels,
382 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000383 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000384 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000385 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100386 bool ReadFrame(FILE* file, Int16FrameData* frame);
387 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
388 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200389 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100390 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000391 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200392 void ProcessDelayVerificationTest(int delay_ms,
393 int system_delay_ms,
394 int delay_min,
395 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700396 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800397 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700398 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800399 void TestChangingForwardChannels(size_t num_in_channels,
400 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700401 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800402 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700403 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000404 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
405 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000406 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000407 int ProcessStreamChooser(Format format);
408 int AnalyzeReverseStreamChooser(Format format);
409 void ProcessDebugDump(const std::string& in_filename,
410 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800411 Format format,
412 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000413 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000414
415 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000416 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200417 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100418 Int16FrameData frame_;
419 Int16FrameData revframe_;
kwiberg62eaacf2016-02-17 06:39:05 -0800420 std::unique_ptr<ChannelBuffer<float> > float_cb_;
421 std::unique_ptr<ChannelBuffer<float> > revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000422 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800423 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000424 FILE* far_file_;
425 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000426 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000427};
428
429ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000430 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200431 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000432 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000433 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000434 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000435 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000436 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200437 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100438 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100439 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100440 apm_config.pipeline.maximum_internal_processing_rate = 48000;
441 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000442}
niklase@google.com470e71d2011-07-07 08:21:25 +0000443
444void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000445 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000446
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000447 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000448}
449
450void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000451 if (far_file_) {
452 ASSERT_EQ(0, fclose(far_file_));
453 }
454 far_file_ = NULL;
455
456 if (near_file_) {
457 ASSERT_EQ(0, fclose(near_file_));
458 }
459 near_file_ = NULL;
460
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000461 if (out_file_) {
462 ASSERT_EQ(0, fclose(out_file_));
463 }
464 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000465}
466
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000467void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200468 ASSERT_EQ(
469 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100470 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200471 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100472 {revframe_.sample_rate_hz, revframe_.num_channels},
473 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000474}
475
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000476void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000477 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000478 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800479 size_t num_input_channels,
480 size_t num_output_channels,
481 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000482 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200483 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000484 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000485 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000486
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200487 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000488 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000489 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000490
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000491 if (far_file_) {
492 ASSERT_EQ(0, fclose(far_file_));
493 }
494 std::string filename = ResourceFilePath("far", sample_rate_hz);
495 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200496 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000497
498 if (near_file_) {
499 ASSERT_EQ(0, fclose(near_file_));
500 }
501 filename = ResourceFilePath("near", sample_rate_hz);
502 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200503 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000504
505 if (open_output_file) {
506 if (out_file_) {
507 ASSERT_EQ(0, fclose(out_file_));
508 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700509 filename = OutputFilePath(
510 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
511 reverse_sample_rate_hz, num_input_channels, num_output_channels,
512 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000513 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200514 ASSERT_TRUE(out_file_ != NULL)
515 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000516 }
517}
518
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000519void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000520 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000521}
522
Jonas Olssona4d87372019-07-05 19:08:33 +0200523bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100524 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000525 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000526 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100527 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200528 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100529 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000530 if (read_count != frame_size) {
531 // Check that the file really ended.
532 EXPECT_NE(0, feof(file));
533 return false; // This is expected.
534 }
535
Per Åhgren2507f8c2020-03-19 12:33:29 +0100536 if (frame->num_channels == 1) {
537 MixStereoToMono(frame->data.data(), frame->data.data(),
538 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000539 }
540
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000541 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000542 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000543 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000544 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000545}
546
Per Åhgren2507f8c2020-03-19 12:33:29 +0100547bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000548 return ReadFrame(file, frame, NULL);
549}
550
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000551// If the end of the file has been reached, rewind it and attempt to read the
552// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200553void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100554 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000555 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200556 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000557 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200558 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000559 }
560}
561
Per Åhgren2507f8c2020-03-19 12:33:29 +0100562void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000563 ReadFrameWithRewind(file, frame, NULL);
564}
565
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000566int ApmTest::ProcessStreamChooser(Format format) {
567 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100568 return apm_->ProcessStream(
569 frame_.data.data(),
570 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
571 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100572 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000573 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200574 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100575 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100576 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100577 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200578 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000579}
580
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000581int ApmTest::AnalyzeReverseStreamChooser(Format format) {
582 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100583 return apm_->ProcessReverseStream(
584 revframe_.data.data(),
585 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
586 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
587 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000588 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000589 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100590 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100591 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000592}
593
Jonas Olssona4d87372019-07-05 19:08:33 +0200594void ApmTest::ProcessDelayVerificationTest(int delay_ms,
595 int system_delay_ms,
596 int delay_min,
597 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200598 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000599 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100600 Int16FrameData tmp_frame;
601 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000602 bool causal = true;
603
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200604 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000605 SetFrameTo(&tmp_frame, 0);
606
607 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200608 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000609 int frame_delay = delay_ms / 10;
610 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100611 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000612 frame->CopyFrom(tmp_frame);
613 frame_queue.push(frame);
614 frame_delay++;
615 causal = false;
616 }
617 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100618 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000619 frame->CopyFrom(tmp_frame);
620 frame_queue.push(frame);
621 frame_delay--;
622 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000623 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
624 // need enough frames with audio to have reliable estimates, but as few as
625 // possible to keep processing time down. 4.5 seconds seemed to be a good
626 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000627 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100628 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000629 frame->CopyFrom(tmp_frame);
630 // Use the near end recording, since that has more speech in it.
631 ASSERT_TRUE(ReadFrame(near_file_, frame));
632 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100633 Int16FrameData* reverse_frame = frame;
634 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000635 if (!causal) {
636 reverse_frame = frame_queue.front();
637 // When we call ProcessStream() the frame is modified, so we can't use the
638 // pointer directly when things are non-causal. Use an intermediate frame
639 // and copy the data.
640 process_frame = &tmp_frame;
641 process_frame->CopyFrom(*frame);
642 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100643 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
644 reverse_frame->data.data(),
645 StreamConfig(reverse_frame->sample_rate_hz,
646 reverse_frame->num_channels),
647 StreamConfig(reverse_frame->sample_rate_hz,
648 reverse_frame->num_channels),
649 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000650 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100651 EXPECT_EQ(apm_->kNoError,
652 apm_->ProcessStream(process_frame->data.data(),
653 StreamConfig(process_frame->sample_rate_hz,
654 process_frame->num_channels),
655 StreamConfig(process_frame->sample_rate_hz,
656 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100657 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000658 frame = frame_queue.front();
659 frame_queue.pop();
660 delete frame;
661
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000662 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000663 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100664 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000665 }
666 }
667
668 rewind(near_file_);
669 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100670 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000671 frame_queue.pop();
672 delete frame;
673 }
674 // Calculate expected delay estimate and acceptable regions. Further,
675 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700676 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100677 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700678 const int expected_median =
679 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
680 const int expected_median_high = rtc::SafeClamp<int>(
681 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700682 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700683 const int expected_median_low = rtc::SafeClamp<int>(
684 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700685 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000686 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100687 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200688 ASSERT_TRUE(stats.delay_median_ms.has_value());
689 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000690 EXPECT_GE(expected_median_high, median);
691 EXPECT_LE(expected_median_low, median);
692}
693
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000694void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000696 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000697
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000698 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200699 AudioProcessing::Config apm_config = apm_->GetConfig();
700 apm_config.gain_controller1.enabled = true;
701 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200702 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000703
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000704 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200705 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000706 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200707 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000708
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000709 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200710 apm_config.echo_canceller.enabled = true;
711 apm_config.echo_canceller.mobile_mode = false;
712 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000713 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200714 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200715 apm_config.gain_controller1.enabled = false;
716 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000717
718 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000719 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100720 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000721
722 // Resets after successful ProcessStream().
723 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000724 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100725 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000726
727 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200728 apm_config.gain_controller1.enabled = true;
729 apm_->ApplyConfig(apm_config);
730 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100731 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200732 apm_config.gain_controller1.enabled = false;
733 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000734
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000735 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200736 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100737 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000738
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000739 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000740 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200741 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000742 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000743}
744
745TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000746 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000747}
748
749TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000750 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000751}
752
Michael Graczyk86c6d332015-07-23 11:41:39 -0700753void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800754 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700755 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100756 frame_.num_channels = num_channels;
757
758 EXPECT_EQ(expected_return,
759 apm_->ProcessStream(
760 frame_.data.data(),
761 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
762 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100763 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100764 EXPECT_EQ(expected_return,
765 apm_->ProcessReverseStream(
766 frame_.data.data(),
767 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
768 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
769 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000770}
771
Michael Graczyk86c6d332015-07-23 11:41:39 -0700772void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800773 size_t num_in_channels,
774 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700775 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100776 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700777 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
778
779 EXPECT_EQ(expected_return,
780 apm_->ProcessStream(float_cb_->channels(), input_stream,
781 output_stream, float_cb_->channels()));
782}
783
784void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800785 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700786 AudioProcessing::Error expected_return) {
787 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100788 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700789 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100790 {frame_.sample_rate_hz, num_rev_channels},
791 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700792
ekmeyerson60d9b332015-08-14 10:35:55 -0700793 EXPECT_EQ(
794 expected_return,
795 apm_->ProcessReverseStream(
796 float_cb_->channels(), processing_config.reverse_input_stream(),
797 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700798}
799
800TEST_F(ApmTest, ChannelsInt16Interface) {
801 // Testing number of invalid and valid channels.
802 Init(16000, 16000, 16000, 4, 4, 4, false);
803
804 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
805
Peter Kasting69558702016-01-12 16:26:35 -0800806 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700807 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000808 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000809 }
810}
811
Michael Graczyk86c6d332015-07-23 11:41:39 -0700812TEST_F(ApmTest, Channels) {
813 // Testing number of invalid and valid channels.
814 Init(16000, 16000, 16000, 4, 4, 4, false);
815
816 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
817 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
818
Peter Kasting69558702016-01-12 16:26:35 -0800819 for (size_t i = 1; i < 4; ++i) {
820 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700821 // Output channels much be one or match input channels.
822 if (j == 1 || i == j) {
823 TestChangingForwardChannels(i, j, kNoErr);
824 TestChangingReverseChannels(i, kNoErr);
825
826 EXPECT_EQ(i, apm_->num_input_channels());
827 EXPECT_EQ(j, apm_->num_output_channels());
828 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800829 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700830 } else {
831 TestChangingForwardChannels(i, j,
832 AudioProcessing::kBadNumberChannelsError);
833 }
834 }
835 }
836}
837
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000838TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100839 // Testing some valid sample rates.
840 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
841 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000842 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000843 }
844}
845
Sam Zackrissone277bde2019-10-25 10:07:54 +0200846// This test repeatedly reconfigures the pre-amplifier in APM, processes a
847// number of frames, and checks that output signal has the right level.
848TEST_F(ApmTest, PreAmplifier) {
849 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200850 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100851 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200852 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100853 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200854 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
855 }
856 }
857 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100858 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200859 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200860
Per Åhgren2507f8c2020-03-19 12:33:29 +0100861 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200862 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
863 return std::accumulate(data.begin(), data.end(), 0.0f,
864 [](float a, float b) { return a + b * b; }) /
865 data.size() / 32768 / 32768;
866 };
867
868 const float input_power = compute_power(tmp_frame);
869 // Double-check that the input data is large compared to the error kEpsilon.
870 constexpr float kEpsilon = 1e-4f;
871 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
872
873 // 1. Enable pre-amp with 0 dB gain.
874 AudioProcessing::Config config = apm_->GetConfig();
875 config.pre_amplifier.enabled = true;
876 config.pre_amplifier.fixed_gain_factor = 1.0f;
877 apm_->ApplyConfig(config);
878
879 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200880 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200881 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
882 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200883 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200884 EXPECT_NEAR(output_power, input_power, kEpsilon);
885 config = apm_->GetConfig();
886 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
887
888 // 2. Change pre-amp gain via ApplyConfig.
889 config.pre_amplifier.fixed_gain_factor = 2.0f;
890 apm_->ApplyConfig(config);
891
892 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200893 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200894 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
895 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200896 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200897 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
898 config = apm_->GetConfig();
899 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
900
901 // 3. Change pre-amp gain via a RuntimeSetting.
902 apm_->SetRuntimeSetting(
903 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
904
905 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200906 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200907 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
908 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200909 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200910 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
911 config = apm_->GetConfig();
912 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
913}
914
Per Åhgrendb5d7282021-03-15 16:31:04 +0000915// This test a simple test that ensures that the emulated analog mic gain
916// functionality runs without crashing.
917TEST_F(ApmTest, AnalogMicGainEmulation) {
918 // Fill the audio frame with a sawtooth pattern.
919 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
920 const size_t samples_per_channel = frame_.samples_per_channel;
921 for (size_t i = 0; i < samples_per_channel; i++) {
922 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
923 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
924 }
925 }
926 // Cache the frame in tmp_frame.
927 Int16FrameData tmp_frame;
928 tmp_frame.CopyFrom(frame_);
929
930 // Enable the analog gain emulation.
931 AudioProcessing::Config config = apm_->GetConfig();
932 config.capture_level_adjustment.enabled = true;
933 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
934 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
935 config.gain_controller1.enabled = true;
936 config.gain_controller1.mode =
937 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
938 config.gain_controller1.analog_gain_controller.enabled = true;
939 apm_->ApplyConfig(config);
940
941 // Process a number of frames to ensure that the code runs without crashes.
942 for (int i = 0; i < 20; ++i) {
943 frame_.CopyFrom(tmp_frame);
944 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
945 }
946}
947
948// This test repeatedly reconfigures the capture level adjustment functionality
949// in APM, processes a number of frames, and checks that output signal has the
950// right level.
951TEST_F(ApmTest, CaptureLevelAdjustment) {
952 // Fill the audio frame with a sawtooth pattern.
953 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
954 const size_t samples_per_channel = frame_.samples_per_channel;
955 for (size_t i = 0; i < samples_per_channel; i++) {
956 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
957 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
958 }
959 }
960 // Cache the frame in tmp_frame.
961 Int16FrameData tmp_frame;
962 tmp_frame.CopyFrom(frame_);
963
964 auto compute_power = [](const Int16FrameData& frame) {
965 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
966 return std::accumulate(data.begin(), data.end(), 0.0f,
967 [](float a, float b) { return a + b * b; }) /
968 data.size() / 32768 / 32768;
969 };
970
971 const float input_power = compute_power(tmp_frame);
972 // Double-check that the input data is large compared to the error kEpsilon.
973 constexpr float kEpsilon = 1e-20f;
974 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
975
976 // 1. Enable pre-amp with 0 dB gain.
977 AudioProcessing::Config config = apm_->GetConfig();
978 config.capture_level_adjustment.enabled = true;
979 config.capture_level_adjustment.pre_gain_factor = 0.5f;
980 config.capture_level_adjustment.post_gain_factor = 4.f;
981 const float expected_output_power1 =
982 config.capture_level_adjustment.pre_gain_factor *
983 config.capture_level_adjustment.pre_gain_factor *
984 config.capture_level_adjustment.post_gain_factor *
985 config.capture_level_adjustment.post_gain_factor * input_power;
986 apm_->ApplyConfig(config);
987
988 for (int i = 0; i < 20; ++i) {
989 frame_.CopyFrom(tmp_frame);
990 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
991 }
992 float output_power = compute_power(frame_);
993 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
994 config = apm_->GetConfig();
995 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
996 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
997
998 // 2. Change pre-amp gain via ApplyConfig.
999 config.capture_level_adjustment.pre_gain_factor = 1.0f;
1000 config.capture_level_adjustment.post_gain_factor = 2.f;
1001 const float expected_output_power2 =
1002 config.capture_level_adjustment.pre_gain_factor *
1003 config.capture_level_adjustment.pre_gain_factor *
1004 config.capture_level_adjustment.post_gain_factor *
1005 config.capture_level_adjustment.post_gain_factor * input_power;
1006 apm_->ApplyConfig(config);
1007
1008 for (int i = 0; i < 20; ++i) {
1009 frame_.CopyFrom(tmp_frame);
1010 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1011 }
1012 output_power = compute_power(frame_);
1013 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1014 config = apm_->GetConfig();
1015 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1016 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1017
1018 // 3. Change pre-amp gain via a RuntimeSetting.
1019 constexpr float kPreGain3 = 0.5f;
1020 constexpr float kPostGain3 = 3.f;
1021 const float expected_output_power3 =
1022 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1023
1024 apm_->SetRuntimeSetting(
1025 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1026 apm_->SetRuntimeSetting(
1027 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1028
1029 for (int i = 0; i < 20; ++i) {
1030 frame_.CopyFrom(tmp_frame);
1031 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1032 }
1033 output_power = compute_power(frame_);
1034 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1035 config = apm_->GetConfig();
1036 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1037 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1038}
1039
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001040TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001041 AudioProcessing::Config config = apm_->GetConfig();
1042 config.gain_controller1.enabled = false;
1043 apm_->ApplyConfig(config);
1044 config.gain_controller1.enabled = true;
1045 apm_->ApplyConfig(config);
1046
niklase@google.com470e71d2011-07-07 08:21:25 +00001047 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001048 for (auto mode :
1049 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1050 AudioProcessing::Config::GainController1::kFixedDigital,
1051 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1052 config.gain_controller1.mode = mode;
1053 apm_->ApplyConfig(config);
1054 apm_->set_stream_analog_level(100);
1055 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001056 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001057
Sam Zackrisson41478c72019-10-15 10:10:26 +02001058 // Testing target levels
1059 for (int target_level_dbfs : {0, 15, 31}) {
1060 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1061 apm_->ApplyConfig(config);
1062 apm_->set_stream_analog_level(100);
1063 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001064 }
1065
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001066 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001067 for (int compression_gain_db : {0, 10, 90}) {
1068 config.gain_controller1.compression_gain_db = compression_gain_db;
1069 apm_->ApplyConfig(config);
1070 apm_->set_stream_analog_level(100);
1071 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001072 }
1073
1074 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001075 for (bool enable : {false, true}) {
1076 config.gain_controller1.enable_limiter = enable;
1077 apm_->ApplyConfig(config);
1078 apm_->set_stream_analog_level(100);
1079 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1080 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001081
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001082 // Testing level limits
Sam Zackrisson41478c72019-10-15 10:10:26 +02001083 std::array<int, 4> kMinLevels = {0, 0, 255, 65000};
1084 std::array<int, 4> kMaxLevels = {255, 1024, 65535, 65535};
1085 for (size_t i = 0; i < kMinLevels.size(); ++i) {
1086 int min_level = kMinLevels[i];
1087 int max_level = kMaxLevels[i];
1088 config.gain_controller1.analog_level_minimum = min_level;
1089 config.gain_controller1.analog_level_maximum = max_level;
1090 apm_->ApplyConfig(config);
1091 apm_->set_stream_analog_level((min_level + max_level) / 2);
1092 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001093 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001094}
1095
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001096#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001097using ApmDeathTest = ApmTest;
1098
1099TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001100 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001101 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001102 config.gain_controller1.target_level_dbfs = -1;
1103 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001104}
1105
Tommia5e07cc2020-05-26 21:40:37 +02001106TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001107 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001108 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001109 config.gain_controller1.target_level_dbfs = 32;
1110 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001111}
1112
Tommia5e07cc2020-05-26 21:40:37 +02001113TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001114 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001115 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001116 config.gain_controller1.compression_gain_db = -1;
1117 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001118}
1119
Tommia5e07cc2020-05-26 21:40:37 +02001120TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001121 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001122 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001123 config.gain_controller1.compression_gain_db = 91;
1124 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001125}
1126
Tommia5e07cc2020-05-26 21:40:37 +02001127TEST_F(ApmDeathTest, GainControlDiesOnTooLowAnalogLevelLowerLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001128 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001129 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001130 config.gain_controller1.analog_level_minimum = -1;
1131 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001132}
1133
Tommia5e07cc2020-05-26 21:40:37 +02001134TEST_F(ApmDeathTest, GainControlDiesOnTooHighAnalogLevelUpperLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001135 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001136 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001137 config.gain_controller1.analog_level_maximum = 65536;
1138 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001139}
1140
Tommia5e07cc2020-05-26 21:40:37 +02001141TEST_F(ApmDeathTest, GainControlDiesOnInvertedAnalogLevelLimits) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001142 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001143 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001144 config.gain_controller1.analog_level_minimum = 512;
1145 config.gain_controller1.analog_level_maximum = 255;
1146 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001147}
1148
Tommia5e07cc2020-05-26 21:40:37 +02001149TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001150 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001151 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001152 config.gain_controller1.analog_level_minimum = 255;
1153 config.gain_controller1.analog_level_maximum = 512;
1154 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001155 EXPECT_DEATH(apm_->set_stream_analog_level(254), "");
1156}
1157
Tommia5e07cc2020-05-26 21:40:37 +02001158TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001159 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001160 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001161 config.gain_controller1.analog_level_minimum = 255;
1162 config.gain_controller1.analog_level_maximum = 512;
1163 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001164 EXPECT_DEATH(apm_->set_stream_analog_level(513), "");
1165}
1166#endif
1167
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001168void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001169 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001170 auto config = apm_->GetConfig();
1171 config.gain_controller1.enabled = true;
1172 config.gain_controller1.mode =
1173 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1174 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001175
1176 int out_analog_level = 0;
1177 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001178 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001179 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001180 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001181
1182 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001183 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001184 EXPECT_EQ(apm_->kNoError,
1185 apm_->ProcessStream(
1186 frame_.data.data(),
1187 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1188 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001189 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001190 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001191 }
1192
1193 // Ensure the AGC is still able to reach the maximum.
1194 EXPECT_EQ(255, out_analog_level);
1195}
1196
1197// Verifies that despite volume slider quantization, the AGC can continue to
1198// increase its volume.
1199TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001200 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001201 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1202 }
1203}
1204
1205void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001206 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001207 auto config = apm_->GetConfig();
1208 config.gain_controller1.enabled = true;
1209 config.gain_controller1.mode =
1210 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1211 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001212
1213 int out_analog_level = 100;
1214 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001215 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001216 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001217 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001218
Sam Zackrisson41478c72019-10-15 10:10:26 +02001219 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001220 EXPECT_EQ(apm_->kNoError,
1221 apm_->ProcessStream(
1222 frame_.data.data(),
1223 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1224 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001225 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001226 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001227 }
1228
1229 // Ensure the volume was raised.
1230 EXPECT_GT(out_analog_level, 100);
1231 int highest_level_reached = out_analog_level;
1232 // Simulate a user manual volume change.
1233 out_analog_level = 100;
1234
1235 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001236 ReadFrameWithRewind(near_file_, &frame_);
1237 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001238
Sam Zackrisson41478c72019-10-15 10:10:26 +02001239 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001240 EXPECT_EQ(apm_->kNoError,
1241 apm_->ProcessStream(
1242 frame_.data.data(),
1243 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1244 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001245 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001246 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001247 // Check that AGC respected the manually adjusted volume.
1248 EXPECT_LT(out_analog_level, highest_level_reached);
1249 }
1250 // Check that the volume was still raised.
1251 EXPECT_GT(out_analog_level, 100);
1252}
1253
1254TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001255 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001256 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1257 }
1258}
1259
niklase@google.com470e71d2011-07-07 08:21:25 +00001260TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001261 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001262 AudioProcessing::Config apm_config;
1263 apm_config.high_pass_filter.enabled = true;
1264 apm_->ApplyConfig(apm_config);
1265 apm_config.high_pass_filter.enabled = false;
1266 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001267}
1268
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001269TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001270 AudioProcessing::Config config = apm_->GetConfig();
1271 EXPECT_FALSE(config.echo_canceller.enabled);
1272 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001273 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001274 EXPECT_FALSE(config.noise_suppression.enabled);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001275 EXPECT_FALSE(config.voice_detection.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001276}
1277
1278TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001279 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001280 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001281 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001282 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001283 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001284 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001285 EXPECT_EQ(apm_->kNoError,
1286 apm_->ProcessStream(
1287 frame_.data.data(),
1288 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1289 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001290 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001291 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001292 EXPECT_EQ(apm_->kNoError,
1293 apm_->ProcessReverseStream(
1294 frame_.data.data(),
1295 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1296 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1297 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001298 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001299 }
1300 }
1301}
1302
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001303TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1304 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001305 const size_t kSamples = 160;
1306 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001307 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001308 float dest[kSamples] = {};
1309
1310 auto src_channels = &src[0];
1311 auto dest_channels = &dest[0];
1312
Niels Möller4f776ac2021-07-02 11:30:54 +02001313 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001314 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1315 StreamConfig(sample_rate, 1),
1316 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001317
1318 for (size_t i = 0; i < kSamples; ++i) {
1319 EXPECT_EQ(src[i], dest[i]);
1320 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001321
1322 // Same for ProcessReverseStream.
1323 float rev_dest[kSamples] = {};
1324 auto rev_dest_channels = &rev_dest[0];
1325
1326 StreamConfig input_stream = {sample_rate, 1};
1327 StreamConfig output_stream = {sample_rate, 1};
1328 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1329 output_stream, &rev_dest_channels));
1330
1331 for (size_t i = 0; i < kSamples; ++i) {
1332 EXPECT_EQ(src[i], rev_dest[i]);
1333 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001334}
1335
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001336TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1337 EnableAllComponents();
1338
pkasting25702cb2016-01-08 13:50:27 -08001339 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001340 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1341 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001342 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001343 ASSERT_EQ(0, feof(far_file_));
1344 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001345 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001346 CopyLeftToRightChannel(revframe_.data.data(),
1347 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001348
Per Åhgren2507f8c2020-03-19 12:33:29 +01001349 ASSERT_EQ(
1350 kNoErr,
1351 apm_->ProcessReverseStream(
1352 revframe_.data.data(),
1353 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1354 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1355 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001356
Per Åhgren2507f8c2020-03-19 12:33:29 +01001357 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001358
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001359 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001360 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001361 ASSERT_EQ(kNoErr,
1362 apm_->ProcessStream(
1363 frame_.data.data(),
1364 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1365 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001366 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001367 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001368
Per Åhgren2507f8c2020-03-19 12:33:29 +01001369 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001370 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001371 rewind(far_file_);
1372 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001373 }
1374}
1375
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001376TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001377 // Verify the filter is not active through undistorted audio when:
1378 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001379 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001380 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001381 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001382 EXPECT_EQ(apm_->kNoError,
1383 apm_->ProcessStream(
1384 frame_.data.data(),
1385 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1386 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001387 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001388 EXPECT_EQ(apm_->kNoError,
1389 apm_->ProcessStream(
1390 frame_.data.data(),
1391 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1392 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001393 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001394 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001395
1396 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001397 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001398 SetFrameTo(&frame_, 1000);
1399 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001400 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001401 EXPECT_EQ(apm_->kNoError,
1402 apm_->ProcessStream(
1403 frame_.data.data(),
1404 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1405 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001406 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001407 EXPECT_EQ(apm_->kNoError,
1408 apm_->ProcessStream(
1409 frame_.data.data(),
1410 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1411 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001412 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001413 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001414 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001415
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001416 // 3. Only GetStatistics-reporting VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001417 SetFrameTo(&frame_, 1000);
1418 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001419 apm_config.voice_detection.enabled = true;
1420 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001421 EXPECT_EQ(apm_->kNoError,
1422 apm_->ProcessStream(
1423 frame_.data.data(),
1424 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1425 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001426 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001427 EXPECT_EQ(apm_->kNoError,
1428 apm_->ProcessStream(
1429 frame_.data.data(),
1430 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1431 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001432 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001433 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001434 apm_config.voice_detection.enabled = false;
1435 apm_->ApplyConfig(apm_config);
1436
Alessio Bazzica183c64c2021-10-19 13:32:02 +02001437 // 4. The VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001438 SetFrameTo(&frame_, 1000);
1439 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001440 apm_config.voice_detection.enabled = true;
1441 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001442 EXPECT_EQ(apm_->kNoError,
1443 apm_->ProcessStream(
1444 frame_.data.data(),
1445 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1446 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001447 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001448 EXPECT_EQ(apm_->kNoError,
1449 apm_->ProcessStream(
1450 frame_.data.data(),
1451 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1452 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001453 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001454 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001455 apm_config.voice_detection.enabled = false;
1456 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001457
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001458 // Check the test is valid. We should have distortion from the filter
1459 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001460 apm_config.echo_canceller.enabled = true;
1461 apm_config.echo_canceller.mobile_mode = false;
1462 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001463 frame_.samples_per_channel = 320;
1464 frame_.num_channels = 2;
1465 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001466 SetFrameTo(&frame_, 1000);
1467 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001468 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001469 EXPECT_EQ(apm_->kNoError,
1470 apm_->ProcessStream(
1471 frame_.data.data(),
1472 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1473 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001474 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001475 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001476}
1477
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001478#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1479void ApmTest::ProcessDebugDump(const std::string& in_filename,
1480 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001481 Format format,
1482 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001483 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001484 FILE* in_file = fopen(in_filename.c_str(), "rb");
1485 ASSERT_TRUE(in_file != NULL);
1486 audioproc::Event event_msg;
1487 bool first_init = true;
1488
1489 while (ReadMessageFromFile(in_file, &event_msg)) {
1490 if (event_msg.type() == audioproc::Event::INIT) {
1491 const audioproc::Init msg = event_msg.init();
1492 int reverse_sample_rate = msg.sample_rate();
1493 if (msg.has_reverse_sample_rate()) {
1494 reverse_sample_rate = msg.reverse_sample_rate();
1495 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001496 int output_sample_rate = msg.sample_rate();
1497 if (msg.has_output_sample_rate()) {
1498 output_sample_rate = msg.output_sample_rate();
1499 }
1500
Jonas Olssona4d87372019-07-05 19:08:33 +02001501 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1502 msg.num_input_channels(), msg.num_output_channels(),
1503 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001504 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001505 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001506 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001507 auto aec_dump =
1508 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1509 EXPECT_TRUE(aec_dump);
1510 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001511 first_init = false;
1512 }
1513
1514 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1515 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1516
1517 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001518 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001519 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001520 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001521 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1522 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001523 }
1524 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001525 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001526 if (format == kFloatFormat) {
1527 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001528 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001529 }
1530 }
1531 AnalyzeReverseStreamChooser(format);
1532
1533 } else if (event_msg.type() == audioproc::Event::STREAM) {
1534 const audioproc::Stream msg = event_msg.stream();
1535 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001536 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001537
Sam Zackrisson41478c72019-10-15 10:10:26 +02001538 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001539 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001540 if (msg.has_keypress()) {
1541 apm_->set_stream_key_pressed(msg.keypress());
1542 } else {
1543 apm_->set_stream_key_pressed(true);
1544 }
1545
1546 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001547 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001548 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001549 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001550 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1551 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001552 }
1553 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001554 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001555 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001556 if (format == kFloatFormat) {
1557 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001558 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001559 }
1560 }
1561 ProcessStreamChooser(format);
1562 }
1563 }
aleloif4dd1912017-06-15 01:55:38 -07001564 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001565 fclose(in_file);
1566}
1567
1568void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001569 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001570 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001571 std::string format_string;
1572 switch (format) {
1573 case kIntFormat:
1574 format_string = "_int";
1575 break;
1576 case kFloatFormat:
1577 format_string = "_float";
1578 break;
1579 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001580 const std::string ref_filename = test::TempFilename(
1581 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1582 const std::string out_filename = test::TempFilename(
1583 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001584 const std::string limited_filename = test::TempFilename(
1585 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1586 const size_t logging_limit_bytes = 100000;
1587 // We expect at least this many bytes in the created logfile.
1588 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001589 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001590 ProcessDebugDump(in_filename, ref_filename, format, -1);
1591 ProcessDebugDump(ref_filename, out_filename, format, -1);
1592 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001593
1594 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1595 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001596 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001597 ASSERT_TRUE(ref_file != NULL);
1598 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001599 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001600 std::unique_ptr<uint8_t[]> ref_bytes;
1601 std::unique_ptr<uint8_t[]> out_bytes;
1602 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001603
1604 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1605 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001606 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001607 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001608 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001609 while (ref_size > 0 && out_size > 0) {
1610 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001611 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001612 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001613 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001614 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001615 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001616 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1617 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001618 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001619 }
1620 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001621 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1622 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001623 EXPECT_NE(0, feof(ref_file));
1624 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001625 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001626 ASSERT_EQ(0, fclose(ref_file));
1627 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001628 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001629 remove(ref_filename.c_str());
1630 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001631 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001632}
1633
pbosc7a65692016-05-06 12:50:04 -07001634TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001635 VerifyDebugDumpTest(kIntFormat);
1636}
1637
pbosc7a65692016-05-06 12:50:04 -07001638TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001639 VerifyDebugDumpTest(kFloatFormat);
1640}
1641#endif
1642
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001643// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001644TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001645 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001646 const std::string filename =
1647 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001648 {
1649 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1650 EXPECT_FALSE(aec_dump);
1651 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001652
1653#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1654 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001655 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001656
aleloif4dd1912017-06-15 01:55:38 -07001657 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1658 EXPECT_TRUE(aec_dump);
1659 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001660 EXPECT_EQ(apm_->kNoError,
1661 apm_->ProcessStream(
1662 frame_.data.data(),
1663 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1664 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001665 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001666 EXPECT_EQ(apm_->kNoError,
1667 apm_->ProcessReverseStream(
1668 revframe_.data.data(),
1669 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1670 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1671 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001672 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001673
1674 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001675 FILE* fid = fopen(filename.c_str(), "r");
1676 ASSERT_TRUE(fid != NULL);
1677
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001678 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001679 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001680 ASSERT_EQ(0, remove(filename.c_str()));
1681#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001682 // Verify the file has NOT been written.
1683 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1684#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1685}
1686
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001687// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001688TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001689 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001690
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001691 const std::string filename =
1692 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001693 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1694 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001695
1696#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1697 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001698 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001699
Niels Möllere8e4dc42019-06-11 14:04:16 +02001700 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001701 EXPECT_TRUE(aec_dump);
1702 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001703 EXPECT_EQ(apm_->kNoError,
1704 apm_->ProcessReverseStream(
1705 revframe_.data.data(),
1706 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1707 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1708 revframe_.data.data()));
1709 EXPECT_EQ(apm_->kNoError,
1710 apm_->ProcessStream(
1711 frame_.data.data(),
1712 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1713 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001714 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001715 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001716
1717 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001718 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001719 ASSERT_TRUE(fid != NULL);
1720
1721 // Clean it up.
1722 ASSERT_EQ(0, fclose(fid));
1723 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001724#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1725}
1726
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001727// TODO(andrew): Add a test to process a few frames with different combinations
1728// of enabled components.
1729
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001730TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001731 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001732 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001733
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001734 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001735 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001736 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001737 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001738 for (size_t i = 0; i < arraysize(kChannels); i++) {
1739 for (size_t j = 0; j < arraysize(kChannels); j++) {
1740 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001741 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001742 test->set_num_reverse_channels(kChannels[i]);
1743 test->set_num_input_channels(kChannels[j]);
1744 test->set_num_output_channels(kChannels[j]);
1745 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001746 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001747 }
1748 }
1749 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001750#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1751 // To test the extended filter mode.
1752 audioproc::Test* test = ref_data.add_test();
1753 test->set_num_reverse_channels(2);
1754 test->set_num_input_channels(2);
1755 test->set_num_output_channels(2);
1756 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1757 test->set_use_aec_extended_filter(true);
1758#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001759 }
1760
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001761 for (int i = 0; i < ref_data.test_size(); i++) {
1762 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001763
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001764 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001765 // TODO(ajm): We no longer allow different input and output channels. Skip
1766 // these tests for now, but they should be removed from the set.
1767 if (test->num_input_channels() != test->num_output_channels())
1768 continue;
1769
Niels Möller4f776ac2021-07-02 11:30:54 +02001770 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001771 AudioProcessing::Config apm_config = apm_->GetConfig();
1772 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1773 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001774
1775 EnableAllComponents();
1776
Jonas Olssona4d87372019-07-05 19:08:33 +02001777 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001778 static_cast<size_t>(test->num_input_channels()),
1779 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001780 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001781
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001782 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001783 int has_voice_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001784 int analog_level = 127;
1785 int analog_level_average = 0;
1786 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001787#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001788 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001789#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001790
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001791 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001792 EXPECT_EQ(
1793 apm_->kNoError,
1794 apm_->ProcessReverseStream(
1795 revframe_.data.data(),
1796 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1797 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1798 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001799
1800 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001801 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001802
Per Åhgren2507f8c2020-03-19 12:33:29 +01001803 EXPECT_EQ(apm_->kNoError,
1804 apm_->ProcessStream(
1805 frame_.data.data(),
1806 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1807 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001808 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001809
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001810 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001811 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001812 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001813
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001814 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001815
Sam Zackrisson41478c72019-10-15 10:10:26 +02001816 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001817 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001818 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001819 EXPECT_TRUE(stats.voice_detected);
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001820 has_voice_count += *stats.voice_detected ? 1 : 0;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001821
Per Åhgren2507f8c2020-03-19 12:33:29 +01001822 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001823 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001824 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001825 ASSERT_EQ(frame_size, write_count);
1826
1827 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001828 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001829 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001830
1831#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1832 const int kStatsAggregationFrameNum = 100; // 1 second.
1833 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001834 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001835 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001836
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001837 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001838 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001839 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001840 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001841 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001842 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001843 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001844 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001845
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001846 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001847 const audioproc::Test::EchoMetrics& reference =
1848 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001849 constexpr float kEpsilon = 0.01;
1850 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1851 EXPECT_NEAR(echo_return_loss_enhancement,
1852 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001853 EXPECT_NEAR(residual_echo_likelihood,
1854 reference.residual_echo_likelihood(), kEpsilon);
1855 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1856 reference.residual_echo_likelihood_recent_max(),
1857 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001858 ++stats_index;
1859 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001860 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1861 message_echo->set_echo_return_loss(echo_return_loss);
1862 message_echo->set_echo_return_loss_enhancement(
1863 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001864 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1865 message_echo->set_residual_echo_likelihood_recent_max(
1866 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001867 }
1868 }
1869#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001870 }
1871 max_output_average /= frame_count;
1872 analog_level_average /= frame_count;
1873
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001874 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001875 const int kIntNear = 1;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001876 // When running the test on a N7 we get a {2, 6} difference of
Artem Titov0b489302021-07-28 20:50:03 +02001877 // `has_voice_count` and `max_output_average` is up to 18 higher.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001878 // All numbers being consistently higher on N7 compare to ref_data.
1879 // TODO(bjornv): If we start getting more of these offsets on Android we
1880 // should consider a different approach. Either using one slack for all,
1881 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001882#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001883 const int kHasVoiceCountOffset = 3;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001884 const int kHasVoiceCountNear = 8;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001885 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001886 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001887#else
1888 const int kHasVoiceCountOffset = 0;
1889 const int kHasVoiceCountNear = kIntNear;
1890 const int kMaxOutputAverageOffset = 0;
1891 const int kMaxOutputAverageNear = kIntNear;
1892#endif
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001893 EXPECT_NEAR(test->has_voice_count(),
Jonas Olssona4d87372019-07-05 19:08:33 +02001894 has_voice_count - kHasVoiceCountOffset, kHasVoiceCountNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001895
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001896 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001897 EXPECT_NEAR(test->max_output_average(),
1898 max_output_average - kMaxOutputAverageOffset,
1899 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001900 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001901 test->set_has_voice_count(has_voice_count);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001902
1903 test->set_analog_level_average(analog_level_average);
1904 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001905 }
1906
1907 rewind(far_file_);
1908 rewind(near_file_);
1909 }
1910
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001911 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001912 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001913 }
1914}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001915
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001916TEST_F(ApmTest, NoErrorsWithKeyboardChannel) {
1917 struct ChannelFormat {
1918 AudioProcessing::ChannelLayout in_layout;
1919 AudioProcessing::ChannelLayout out_layout;
1920 };
1921 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02001922 {AudioProcessing::kMonoAndKeyboard, AudioProcessing::kMono},
1923 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kMono},
1924 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kStereo},
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001925 };
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001926
Niels Möller4f776ac2021-07-02 11:30:54 +02001927 rtc::scoped_refptr<AudioProcessing> ap =
1928 AudioProcessingBuilderForTesting().Create();
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001929 // Enable one component just to ensure some processing takes place.
saza0bad15f2019-10-16 11:46:11 +02001930 AudioProcessing::Config config;
1931 config.noise_suppression.enabled = true;
1932 ap->ApplyConfig(config);
pkasting25702cb2016-01-08 13:50:27 -08001933 for (size_t i = 0; i < arraysize(cf); ++i) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001934 const int in_rate = 44100;
1935 const int out_rate = 48000;
1936 ChannelBuffer<float> in_cb(SamplesFromRate(in_rate),
1937 TotalChannelsFromLayout(cf[i].in_layout));
1938 ChannelBuffer<float> out_cb(SamplesFromRate(out_rate),
1939 ChannelsFromLayout(cf[i].out_layout));
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001940 bool has_keyboard = cf[i].in_layout == AudioProcessing::kMonoAndKeyboard ||
1941 cf[i].in_layout == AudioProcessing::kStereoAndKeyboard;
1942 StreamConfig in_sc(in_rate, ChannelsFromLayout(cf[i].in_layout),
1943 has_keyboard);
1944 StreamConfig out_sc(out_rate, ChannelsFromLayout(cf[i].out_layout));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001945
1946 // Run over a few chunks.
1947 for (int j = 0; j < 10; ++j) {
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001948 EXPECT_NOERR(ap->ProcessStream(in_cb.channels(), in_sc, out_sc,
1949 out_cb.channels()));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001950 }
1951 }
1952}
1953
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001954// Compares the reference and test arrays over a region around the expected
1955// delay. Finds the highest SNR in that region and adds the variance and squared
1956// error results to the supplied accumulators.
1957void UpdateBestSNR(const float* ref,
1958 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001959 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001960 int expected_delay,
1961 double* variance_acc,
1962 double* sq_error_acc) {
1963 double best_snr = std::numeric_limits<double>::min();
1964 double best_variance = 0;
1965 double best_sq_error = 0;
1966 // Search over a region of eight samples around the expected delay.
1967 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1968 ++delay) {
1969 double sq_error = 0;
1970 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001971 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001972 double error = test[i + delay] - ref[i];
1973 sq_error += error * error;
1974 variance += ref[i] * ref[i];
1975 }
1976
1977 if (sq_error == 0) {
1978 *variance_acc += variance;
1979 return;
1980 }
1981 double snr = variance / sq_error;
1982 if (snr > best_snr) {
1983 best_snr = snr;
1984 best_variance = variance;
1985 best_sq_error = sq_error;
1986 }
1987 }
1988
1989 *variance_acc += best_variance;
1990 *sq_error_acc += best_sq_error;
1991}
1992
1993// Used to test a multitude of sample rate and channel combinations. It works
1994// by first producing a set of reference files (in SetUpTestCase) that are
1995// assumed to be correct, as the used parameters are verified by other tests
1996// in this collection. Primarily the reference files are all produced at
1997// "native" rates which do not involve any resampling.
1998
1999// Each test pass produces an output file with a particular format. The output
2000// is matched against the reference file closest to its internal processing
2001// format. If necessary the output is resampled back to its process format.
2002// Due to the resampling distortion, we don't expect identical results, but
2003// enforce SNR thresholds which vary depending on the format. 0 is a special
2004// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02002005typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002006class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002007 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002008 public:
2009 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02002010 : input_rate_(std::get<0>(GetParam())),
2011 output_rate_(std::get<1>(GetParam())),
2012 reverse_input_rate_(std::get<2>(GetParam())),
2013 reverse_output_rate_(std::get<3>(GetParam())),
2014 expected_snr_(std::get<4>(GetParam())),
2015 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002016
2017 virtual ~AudioProcessingTest() {}
2018
Mirko Bonadei71061bc2019-06-04 09:01:51 +02002019 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002020 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07002021 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08002022 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08002023 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
2024 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
2025 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002026 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07002027 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
2028 kNativeRates[i], kNumChannels[j], kNumChannels[j],
2029 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002030 }
2031 }
2032 }
2033 }
2034
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02002035 void TearDown() {
2036 // Remove "out" files after each test.
2037 ClearTempOutFiles();
2038 }
2039
Mirko Bonadei71061bc2019-06-04 09:01:51 +02002040 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07002041
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002042 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02002043 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07002044 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002045 static void ProcessFormat(int input_rate,
2046 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07002047 int reverse_input_rate,
2048 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08002049 size_t num_input_channels,
2050 size_t num_output_channels,
2051 size_t num_reverse_input_channels,
2052 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02002053 const std::string& output_file_prefix) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002054 rtc::scoped_refptr<AudioProcessing> ap =
2055 AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01002056 AudioProcessing::Config apm_config = ap->GetConfig();
2057 apm_config.gain_controller1.analog_gain_controller.enabled = false;
2058 ap->ApplyConfig(apm_config);
2059
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002060 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002061
ekmeyerson60d9b332015-08-14 10:35:55 -07002062 ProcessingConfig processing_config = {
2063 {{input_rate, num_input_channels},
2064 {output_rate, num_output_channels},
2065 {reverse_input_rate, num_reverse_input_channels},
2066 {reverse_output_rate, num_reverse_output_channels}}};
2067 ap->Initialize(processing_config);
2068
2069 FILE* far_file =
2070 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002071 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02002072 FILE* out_file = fopen(
2073 OutputFilePath(
2074 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2075 reverse_output_rate, num_input_channels, num_output_channels,
2076 num_reverse_input_channels, num_reverse_output_channels, kForward)
2077 .c_str(),
2078 "wb");
2079 FILE* rev_out_file = fopen(
2080 OutputFilePath(
2081 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2082 reverse_output_rate, num_input_channels, num_output_channels,
2083 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2084 .c_str(),
2085 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002086 ASSERT_TRUE(far_file != NULL);
2087 ASSERT_TRUE(near_file != NULL);
2088 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002089 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002090
2091 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
2092 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002093 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
2094 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002095 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
2096 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002097 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
2098 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002099
2100 // Temporary buffers.
2101 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002102 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2103 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08002104 std::unique_ptr<float[]> float_data(new float[max_length]);
2105 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002106
2107 int analog_level = 127;
2108 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2109 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002110 EXPECT_NOERR(ap->ProcessReverseStream(
2111 rev_cb.channels(), processing_config.reverse_input_stream(),
2112 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002113
2114 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002115 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002116
2117 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002118 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2119 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002120
ekmeyerson60d9b332015-08-14 10:35:55 -07002121 // Dump forward output to file.
2122 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002123 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002124 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002125
Jonas Olssona4d87372019-07-05 19:08:33 +02002126 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2127 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002128
ekmeyerson60d9b332015-08-14 10:35:55 -07002129 // Dump reverse output to file.
2130 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2131 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002132 size_t rev_out_length =
2133 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002134
Jonas Olssona4d87372019-07-05 19:08:33 +02002135 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2136 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002137
Sam Zackrisson41478c72019-10-15 10:10:26 +02002138 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002139 }
2140 fclose(far_file);
2141 fclose(near_file);
2142 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002143 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002144 }
2145
2146 protected:
2147 int input_rate_;
2148 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002149 int reverse_input_rate_;
2150 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002151 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002152 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002153};
2154
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002155TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002156 struct ChannelFormat {
2157 int num_input;
2158 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002159 int num_reverse_input;
2160 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002161 };
2162 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002163 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2164 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002165 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002166
pkasting25702cb2016-01-08 13:50:27 -08002167 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002168 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2169 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2170 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002171
ekmeyerson60d9b332015-08-14 10:35:55 -07002172 // Verify output for both directions.
2173 std::vector<StreamDirection> stream_directions;
2174 stream_directions.push_back(kForward);
2175 stream_directions.push_back(kReverse);
2176 for (StreamDirection file_direction : stream_directions) {
2177 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2178 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2179 const int out_num =
2180 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2181 const double expected_snr =
2182 file_direction ? expected_reverse_snr_ : expected_snr_;
2183
2184 const int min_ref_rate = std::min(in_rate, out_rate);
2185 int ref_rate;
2186
2187 if (min_ref_rate > 32000) {
2188 ref_rate = 48000;
2189 } else if (min_ref_rate > 16000) {
2190 ref_rate = 32000;
2191 } else if (min_ref_rate > 8000) {
2192 ref_rate = 16000;
2193 } else {
2194 ref_rate = 8000;
2195 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002196
ekmeyerson60d9b332015-08-14 10:35:55 -07002197 FILE* out_file = fopen(
2198 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2199 reverse_output_rate_, cf[i].num_input,
2200 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002201 cf[i].num_reverse_output, file_direction)
2202 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002203 "rb");
2204 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002205 FILE* ref_file =
2206 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2207 cf[i].num_output, cf[i].num_output,
2208 cf[i].num_reverse_output,
2209 cf[i].num_reverse_output, file_direction)
2210 .c_str(),
2211 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002212 ASSERT_TRUE(out_file != NULL);
2213 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002214
pkasting25702cb2016-01-08 13:50:27 -08002215 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2216 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002217 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002218 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002219 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002220 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002221 // Data from the resampled output, in case the reference and output rates
2222 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002223 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002224
ekmeyerson60d9b332015-08-14 10:35:55 -07002225 PushResampler<float> resampler;
2226 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002227
ekmeyerson60d9b332015-08-14 10:35:55 -07002228 // Compute the resampling delay of the output relative to the reference,
2229 // to find the region over which we should search for the best SNR.
2230 float expected_delay_sec = 0;
2231 if (in_rate != ref_rate) {
2232 // Input resampling delay.
2233 expected_delay_sec +=
2234 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2235 }
2236 if (out_rate != ref_rate) {
2237 // Output resampling delay.
2238 expected_delay_sec +=
2239 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2240 // Delay of converting the output back to its processing rate for
2241 // testing.
2242 expected_delay_sec +=
2243 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2244 }
2245 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002246 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002247
ekmeyerson60d9b332015-08-14 10:35:55 -07002248 double variance = 0;
2249 double sq_error = 0;
2250 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2251 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2252 float* out_ptr = out_data.get();
2253 if (out_rate != ref_rate) {
2254 // Resample the output back to its internal processing rate if
2255 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002256 ASSERT_EQ(ref_length,
2257 static_cast<size_t>(resampler.Resample(
2258 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002259 out_ptr = cmp_data.get();
2260 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002261
Artem Titov0b489302021-07-28 20:50:03 +02002262 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002263 // SNR of reference vs output.
2264 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2265 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002266 }
2267
ekmeyerson60d9b332015-08-14 10:35:55 -07002268 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2269 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2270 << cf[i].num_input << ", " << cf[i].num_output << ", "
2271 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2272 << ", " << file_direction << "): ";
2273 if (sq_error > 0) {
2274 double snr = 10 * log10(variance / sq_error);
2275 EXPECT_GE(snr, expected_snr);
2276 EXPECT_NE(0, expected_snr);
2277 std::cout << "SNR=" << snr << " dB" << std::endl;
2278 } else {
aluebs776593b2016-03-15 14:04:58 -07002279 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002280 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002281
ekmeyerson60d9b332015-08-14 10:35:55 -07002282 fclose(out_file);
2283 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002284 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002285 }
2286}
2287
2288#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002289INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002290 CommonFormats,
2291 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002292 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2293 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2294 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2295 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2296 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2297 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2298 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2299 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2300 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2301 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2302 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2303 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002304
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002305 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2306 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2307 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2308 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2309 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2310 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2311 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2312 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2313 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2314 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2315 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2316 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002317
Per Åhgrenc0424252019-12-10 13:04:15 +01002318 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2319 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2320 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002321 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2322 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2323 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2324 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2325 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002326 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002327 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2328 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2329 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002330
Per Åhgrenc0424252019-12-10 13:04:15 +01002331 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2332 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2333 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002334 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2335 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2336 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2337 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2338 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2339 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2340 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002341 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002342 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002343
2344#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002345INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002346 CommonFormats,
2347 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002348 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2349 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2350 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002351 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2352 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2353 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002354 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2355 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2356 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002357 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2358 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2359 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002360
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002361 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2362 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2363 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2364 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2365 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2366 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002367 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2368 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2369 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2370 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2371 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2372 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002373
Per Åhgrenc0424252019-12-10 13:04:15 +01002374 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2375 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2376 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002377 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2378 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2379 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002380 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002381 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002382 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002383 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2384 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2385 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002386
Per Åhgrenc0424252019-12-10 13:04:15 +01002387 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2388 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2389 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002390 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2391 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2392 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002393 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002394 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002395 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002396 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2397 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002398 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002399#endif
2400
Per Åhgren3e8bf282019-08-29 23:38:40 +02002401// Produces a scoped trace debug output.
2402std::string ProduceDebugText(int render_input_sample_rate_hz,
2403 int render_output_sample_rate_hz,
2404 int capture_input_sample_rate_hz,
2405 int capture_output_sample_rate_hz,
2406 size_t render_input_num_channels,
2407 size_t render_output_num_channels,
2408 size_t capture_input_num_channels,
2409 size_t capture_output_num_channels) {
2410 rtc::StringBuilder ss;
2411 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002412 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002413 << render_input_sample_rate_hz
2414 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002415 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002416 << render_output_sample_rate_hz
2417 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002418 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002419 << capture_input_sample_rate_hz
2420 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002421 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002422 << capture_output_sample_rate_hz
2423 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002424 "\nNumber of channels:"
2425 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002426 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002427 << "\n Render output: " << render_output_num_channels
2428 << "\n Capture input: " << capture_input_num_channels
2429 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002430 return ss.Release();
2431}
2432
2433// Validates that running the audio processing module using various combinations
2434// of sample rates and number of channels works as intended.
2435void RunApmRateAndChannelTest(
2436 rtc::ArrayView<const int> sample_rates_hz,
2437 rtc::ArrayView<const int> render_channel_counts,
2438 rtc::ArrayView<const int> capture_channel_counts) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002439 rtc::scoped_refptr<AudioProcessing> apm =
2440 AudioProcessingBuilderForTesting().Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002441 webrtc::AudioProcessing::Config apm_config;
2442 apm_config.echo_canceller.enabled = true;
2443 apm->ApplyConfig(apm_config);
2444
2445 StreamConfig render_input_stream_config;
2446 StreamConfig render_output_stream_config;
2447 StreamConfig capture_input_stream_config;
2448 StreamConfig capture_output_stream_config;
2449
2450 std::vector<float> render_input_frame_channels;
2451 std::vector<float*> render_input_frame;
2452 std::vector<float> render_output_frame_channels;
2453 std::vector<float*> render_output_frame;
2454 std::vector<float> capture_input_frame_channels;
2455 std::vector<float*> capture_input_frame;
2456 std::vector<float> capture_output_frame_channels;
2457 std::vector<float*> capture_output_frame;
2458
2459 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2460 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2461 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2462 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2463 for (size_t render_input_num_channels : render_channel_counts) {
2464 for (size_t capture_input_num_channels : capture_channel_counts) {
2465 size_t render_output_num_channels = render_input_num_channels;
2466 size_t capture_output_num_channels = capture_input_num_channels;
2467 auto populate_audio_frame = [](int sample_rate_hz,
2468 size_t num_channels,
2469 StreamConfig* cfg,
2470 std::vector<float>* channels_data,
2471 std::vector<float*>* frame_data) {
2472 cfg->set_sample_rate_hz(sample_rate_hz);
2473 cfg->set_num_channels(num_channels);
2474 cfg->set_has_keyboard(false);
2475
2476 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2477 channels_data->resize(num_channels * max_frame_size);
2478 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2479 frame_data->resize(num_channels);
2480 for (size_t channel = 0; channel < num_channels; ++channel) {
2481 (*frame_data)[channel] =
2482 &(*channels_data)[channel * max_frame_size];
2483 }
2484 };
2485
2486 populate_audio_frame(
2487 render_input_sample_rate_hz, render_input_num_channels,
2488 &render_input_stream_config, &render_input_frame_channels,
2489 &render_input_frame);
2490 populate_audio_frame(
2491 render_output_sample_rate_hz, render_output_num_channels,
2492 &render_output_stream_config, &render_output_frame_channels,
2493 &render_output_frame);
2494 populate_audio_frame(
2495 capture_input_sample_rate_hz, capture_input_num_channels,
2496 &capture_input_stream_config, &capture_input_frame_channels,
2497 &capture_input_frame);
2498 populate_audio_frame(
2499 capture_output_sample_rate_hz, capture_output_num_channels,
2500 &capture_output_stream_config, &capture_output_frame_channels,
2501 &capture_output_frame);
2502
2503 for (size_t frame = 0; frame < 2; ++frame) {
2504 SCOPED_TRACE(ProduceDebugText(
2505 render_input_sample_rate_hz, render_output_sample_rate_hz,
2506 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2507 render_input_num_channels, render_output_num_channels,
2508 render_input_num_channels, capture_output_num_channels));
2509
2510 int result = apm->ProcessReverseStream(
2511 &render_input_frame[0], render_input_stream_config,
2512 render_output_stream_config, &render_output_frame[0]);
2513 EXPECT_EQ(result, AudioProcessing::kNoError);
2514 result = apm->ProcessStream(
2515 &capture_input_frame[0], capture_input_stream_config,
2516 capture_output_stream_config, &capture_output_frame[0]);
2517 EXPECT_EQ(result, AudioProcessing::kNoError);
2518 }
2519 }
2520 }
2521 }
2522 }
2523 }
2524 }
2525}
2526
Alessio Bazzica3438a932020-10-14 12:47:50 +02002527constexpr void Toggle(bool& b) {
2528 b ^= true;
2529}
2530
niklase@google.com470e71d2011-07-07 08:21:25 +00002531} // namespace
peahc19f3122016-10-07 14:54:10 -07002532
Alessio Bazzicac054e782018-04-16 12:10:09 +02002533TEST(RuntimeSettingTest, TestDefaultCtor) {
2534 auto s = AudioProcessing::RuntimeSetting();
2535 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2536}
2537
Alessio Bazzicac054e782018-04-16 12:10:09 +02002538TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2539 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2540 auto s = AudioProcessing::RuntimeSetting();
2541 ASSERT_TRUE(q.Insert(&s));
2542 ASSERT_TRUE(q.Remove(&s));
2543 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2544}
2545
Sam Zackrisson0beac582017-09-25 12:04:02 +02002546TEST(ApmConfiguration, EnablePostProcessing) {
2547 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002548 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002549 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002550 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002551 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002552 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002553 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002554 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002555 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002556
Per Åhgren2507f8c2020-03-19 12:33:29 +01002557 Int16FrameData audio;
2558 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002559 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2560
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002561 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002562 apm->ProcessStream(audio.data.data(),
2563 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2564 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002565 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002566}
2567
Alex Loiko5825aa62017-12-18 16:02:40 +01002568TEST(ApmConfiguration, EnablePreProcessing) {
2569 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002570 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002571 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002572 auto mock_pre_processor =
2573 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002574 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002575 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002576 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002577 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002578
Per Åhgren2507f8c2020-03-19 12:33:29 +01002579 Int16FrameData audio;
2580 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002581 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2582
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002583 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002584 apm->ProcessReverseStream(
2585 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2586 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2587 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002588}
2589
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002590TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2591 // Verify that apm uses a capture analyzer if one is provided.
2592 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002593 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002594 auto mock_capture_analyzer =
2595 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2596 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002597 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002598 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2599 .Create();
2600
Per Åhgren2507f8c2020-03-19 12:33:29 +01002601 Int16FrameData audio;
2602 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002603 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2604
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002605 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002606 apm->ProcessStream(audio.data.data(),
2607 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2608 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002609 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002610}
2611
Alex Loiko73ec0192018-05-15 10:52:28 +02002612TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2613 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002614 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002615 auto mock_pre_processor =
2616 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2617 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002618 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002619 .SetRenderPreProcessing(std::move(mock_pre_processor))
2620 .Create();
2621 apm->SetRuntimeSetting(
2622 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2623
2624 // RuntimeSettings forwarded during 'Process*Stream' calls.
2625 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002626 Int16FrameData audio;
2627 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002628 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2629
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002630 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2631 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002632 apm->ProcessReverseStream(
2633 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2634 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2635 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002636}
2637
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002638class MyEchoControlFactory : public EchoControlFactory {
2639 public:
2640 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2641 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002642 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2643 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002644 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2645 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002646 return std::unique_ptr<EchoControl>(ec);
2647 }
Per Åhgrence202a02019-09-02 17:01:19 +02002648
2649 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002650 int num_render_channels,
2651 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002652 return Create(sample_rate_hz);
2653 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002654};
2655
2656TEST(ApmConfiguration, EchoControlInjection) {
2657 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002658 std::unique_ptr<EchoControlFactory> echo_control_factory(
2659 new MyEchoControlFactory());
2660
Alex Loiko5825aa62017-12-18 16:02:40 +01002661 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002662 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002663 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002664 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002665
Per Åhgren2507f8c2020-03-19 12:33:29 +01002666 Int16FrameData audio;
2667 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002668 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002669 apm->ProcessStream(audio.data.data(),
2670 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2671 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002672 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002673 apm->ProcessReverseStream(
2674 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2675 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2676 audio.data.data());
2677 apm->ProcessStream(audio.data.data(),
2678 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2679 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002680 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002681}
Ivo Creusenae026092017-11-20 13:07:16 +01002682
Niels Möller4f776ac2021-07-02 11:30:54 +02002683rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002684 rtc::scoped_refptr<AudioProcessing> apm =
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002685 AudioProcessingBuilderForTesting().Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002686 if (!apm) {
2687 return apm;
2688 }
2689
2690 ProcessingConfig processing_config = {
2691 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2692
2693 if (apm->Initialize(processing_config) != 0) {
2694 return nullptr;
2695 }
2696
2697 // Disable all components except for an AEC and the residual echo detector.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002698 AudioProcessing::Config apm_config;
2699 apm_config.residual_echo_detector.enabled = true;
2700 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002701 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002702 apm_config.gain_controller2.enabled = false;
2703 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002704 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002705 apm_config.noise_suppression.enabled = false;
saza0bad15f2019-10-16 11:46:11 +02002706 apm_config.voice_detection.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002707 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002708 return apm;
2709}
2710
2711#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2712#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2713#else
2714#define MAYBE_ApmStatistics ApmStatistics
2715#endif
2716
Per Åhgren8607f842019-04-12 22:02:26 +02002717TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2718 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002719 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002720 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002721 AudioProcessing::Config apm_config;
2722 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002723 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002724
2725 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002726 Int16FrameData frame;
2727 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002728 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002729
2730 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002731 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002732 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2733 ptr[i] = 10000 * ((i % 3) - 1);
2734 }
2735
2736 // Do some processing.
2737 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002738 EXPECT_EQ(apm->ProcessReverseStream(
2739 frame.data.data(),
2740 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2741 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2742 frame.data.data()),
2743 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002744 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002745 EXPECT_EQ(apm->ProcessStream(
2746 frame.data.data(),
2747 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2748 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002749 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002750 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002751 }
2752
2753 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002754 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002755 // We expect all statistics to be set and have a sensible value.
2756 ASSERT_TRUE(stats.residual_echo_likelihood);
2757 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2758 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2759 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max);
2760 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2761 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2762 ASSERT_TRUE(stats.echo_return_loss);
2763 EXPECT_NE(*stats.echo_return_loss, -100.0);
2764 ASSERT_TRUE(stats.echo_return_loss_enhancement);
2765 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002766}
2767
2768TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2769 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002770 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002771 ASSERT_TRUE(apm);
2772
2773 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002774 Int16FrameData frame;
2775 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002776 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002777
2778 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002779 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002780 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2781 ptr[i] = 10000 * ((i % 3) - 1);
2782 }
2783
2784 // Do some processing.
2785 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002786 EXPECT_EQ(apm->ProcessReverseStream(
2787 frame.data.data(),
2788 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2789 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2790 frame.data.data()),
2791 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002792 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002793 EXPECT_EQ(apm->ProcessStream(
2794 frame.data.data(),
2795 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2796 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002797 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002798 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002799 }
2800
2801 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002802 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002803 // We expect only the residual echo detector statistics to be set and have a
2804 // sensible value.
2805 EXPECT_TRUE(stats.residual_echo_likelihood);
2806 if (stats.residual_echo_likelihood) {
2807 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2808 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2809 }
2810 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max);
2811 if (stats.residual_echo_likelihood_recent_max) {
2812 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2813 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2814 }
2815 EXPECT_FALSE(stats.echo_return_loss);
2816 EXPECT_FALSE(stats.echo_return_loss_enhancement);
Ivo Creusenae026092017-11-20 13:07:16 +01002817}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002818
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002819TEST(ApmStatistics, ReportHasVoice) {
2820 ProcessingConfig processing_config = {
2821 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2822 AudioProcessing::Config config;
2823
2824 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002825 Int16FrameData frame;
2826 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002827 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2828
2829 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002830 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002831 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2832 ptr[i] = 10000 * ((i % 3) - 1);
2833 }
2834
Niels Möller4f776ac2021-07-02 11:30:54 +02002835 rtc::scoped_refptr<AudioProcessing> apm =
2836 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002837 apm->Initialize(processing_config);
2838
2839 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002840 EXPECT_EQ(
2841 apm->ProcessStream(frame.data.data(),
2842 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2843 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002844 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002845 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002846 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002847
2848 // If enabled, metrics should be reported.
2849 config.voice_detection.enabled = true;
2850 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002851 EXPECT_EQ(
2852 apm->ProcessStream(frame.data.data(),
2853 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2854 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002855 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002856 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002857 auto stats = apm->GetStatistics();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002858 EXPECT_TRUE(stats.voice_detected);
2859
2860 // If re-disabled, the value is again not reported.
2861 config.voice_detection.enabled = false;
2862 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002863 EXPECT_EQ(
2864 apm->ProcessStream(frame.data.data(),
2865 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2866 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002867 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002868 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002869 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002870}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002871
2872TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2873 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2874 std::array<int, 2> render_channel_counts = {1, 7};
2875 std::array<int, 2> capture_channel_counts = {1, 7};
2876 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2877 capture_channel_counts);
2878}
2879
2880TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2881 std::array<int, 1> sample_rates_hz = {48000};
2882 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2883 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2884 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2885 capture_channel_counts);
2886}
2887
2888TEST(ApmConfiguration, HandlingOfRateCombinations) {
2889 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2890 48000, 96000, 192000, 384000};
2891 std::array<int, 1> render_channel_counts = {2};
2892 std::array<int, 1> capture_channel_counts = {2};
2893 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2894 capture_channel_counts);
2895}
2896
Yves Gerey1fce3f82019-12-05 17:45:31 +01002897TEST(ApmConfiguration, SelfAssignment) {
2898 // At some point memory sanitizer was complaining about self-assigment.
2899 // Make sure we don't regress.
2900 AudioProcessing::Config config;
2901 AudioProcessing::Config* config2 = &config;
2902 *config2 = *config2; // Workaround -Wself-assign-overloaded
2903 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2904}
2905
Alessio Bazzica3438a932020-10-14 12:47:50 +02002906TEST(AudioProcessing, GainController1ConfigEqual) {
2907 AudioProcessing::Config::GainController1 a;
2908 AudioProcessing::Config::GainController1 b;
2909 EXPECT_EQ(a, b);
2910
2911 Toggle(a.enabled);
2912 b.enabled = a.enabled;
2913 EXPECT_EQ(a, b);
2914
2915 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2916 b.mode = a.mode;
2917 EXPECT_EQ(a, b);
2918
2919 a.target_level_dbfs++;
2920 b.target_level_dbfs = a.target_level_dbfs;
2921 EXPECT_EQ(a, b);
2922
2923 a.compression_gain_db++;
2924 b.compression_gain_db = a.compression_gain_db;
2925 EXPECT_EQ(a, b);
2926
2927 Toggle(a.enable_limiter);
2928 b.enable_limiter = a.enable_limiter;
2929 EXPECT_EQ(a, b);
2930
2931 a.analog_level_minimum++;
2932 b.analog_level_minimum = a.analog_level_minimum;
2933 EXPECT_EQ(a, b);
2934
2935 a.analog_level_maximum--;
2936 b.analog_level_maximum = a.analog_level_maximum;
2937 EXPECT_EQ(a, b);
2938
2939 auto& a_analog = a.analog_gain_controller;
2940 auto& b_analog = b.analog_gain_controller;
2941
2942 Toggle(a_analog.enabled);
2943 b_analog.enabled = a_analog.enabled;
2944 EXPECT_EQ(a, b);
2945
2946 a_analog.startup_min_volume++;
2947 b_analog.startup_min_volume = a_analog.startup_min_volume;
2948 EXPECT_EQ(a, b);
2949
2950 a_analog.clipped_level_min++;
2951 b_analog.clipped_level_min = a_analog.clipped_level_min;
2952 EXPECT_EQ(a, b);
2953
Alessio Bazzica3438a932020-10-14 12:47:50 +02002954 Toggle(a_analog.enable_digital_adaptive);
2955 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2956 EXPECT_EQ(a, b);
2957}
2958
2959// Checks that one differing parameter is sufficient to make two configs
2960// different.
2961TEST(AudioProcessing, GainController1ConfigNotEqual) {
2962 AudioProcessing::Config::GainController1 a;
2963 const AudioProcessing::Config::GainController1 b;
2964
2965 Toggle(a.enabled);
2966 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002967 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002968
2969 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2970 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002971 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002972
2973 a.target_level_dbfs++;
2974 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002975 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002976
2977 a.compression_gain_db++;
2978 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002979 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002980
2981 Toggle(a.enable_limiter);
2982 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002983 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002984
2985 a.analog_level_minimum++;
2986 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002987 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002988
2989 a.analog_level_maximum--;
2990 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002991 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002992
2993 auto& a_analog = a.analog_gain_controller;
2994 const auto& b_analog = b.analog_gain_controller;
2995
2996 Toggle(a_analog.enabled);
2997 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002998 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002999
3000 a_analog.startup_min_volume++;
3001 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003002 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003003
3004 a_analog.clipped_level_min++;
3005 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003006 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003007
Alessio Bazzica3438a932020-10-14 12:47:50 +02003008 Toggle(a_analog.enable_digital_adaptive);
3009 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003010 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003011}
3012
3013TEST(AudioProcessing, GainController2ConfigEqual) {
3014 AudioProcessing::Config::GainController2 a;
3015 AudioProcessing::Config::GainController2 b;
3016 EXPECT_EQ(a, b);
3017
3018 Toggle(a.enabled);
3019 b.enabled = a.enabled;
3020 EXPECT_EQ(a, b);
3021
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003022 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003023 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3024 EXPECT_EQ(a, b);
3025
3026 auto& a_adaptive = a.adaptive_digital;
3027 auto& b_adaptive = b.adaptive_digital;
3028
3029 Toggle(a_adaptive.enabled);
3030 b_adaptive.enabled = a_adaptive.enabled;
3031 EXPECT_EQ(a, b);
3032
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003033 Toggle(a_adaptive.dry_run);
3034 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003035 EXPECT_EQ(a, b);
3036
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003037 a_adaptive.headroom_db += 1.0f;
3038 b_adaptive.headroom_db = a_adaptive.headroom_db;
3039 EXPECT_EQ(a, b);
3040
3041 a_adaptive.max_gain_db += 1.0f;
3042 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3043 EXPECT_EQ(a, b);
3044
3045 a_adaptive.initial_gain_db += 1.0f;
3046 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3047 EXPECT_EQ(a, b);
3048
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003049 a_adaptive.vad_reset_period_ms++;
3050 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003051 EXPECT_EQ(a, b);
3052
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003053 a_adaptive.adjacent_speech_frames_threshold++;
3054 b_adaptive.adjacent_speech_frames_threshold =
3055 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003056 EXPECT_EQ(a, b);
3057
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003058 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003059 b_adaptive.max_gain_change_db_per_second =
3060 a_adaptive.max_gain_change_db_per_second;
3061 EXPECT_EQ(a, b);
3062
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003063 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003064 b_adaptive.max_output_noise_level_dbfs =
3065 a_adaptive.max_output_noise_level_dbfs;
3066 EXPECT_EQ(a, b);
3067}
3068
3069// Checks that one differing parameter is sufficient to make two configs
3070// different.
3071TEST(AudioProcessing, GainController2ConfigNotEqual) {
3072 AudioProcessing::Config::GainController2 a;
3073 const AudioProcessing::Config::GainController2 b;
3074
3075 Toggle(a.enabled);
3076 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003077 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003078
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003079 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003080 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003081 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003082
3083 auto& a_adaptive = a.adaptive_digital;
3084 const auto& b_adaptive = b.adaptive_digital;
3085
3086 Toggle(a_adaptive.enabled);
3087 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003088 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003089
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003090 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003091 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003092 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003093
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003094 a_adaptive.headroom_db += 1.0f;
3095 EXPECT_NE(a, b);
3096 a_adaptive = b_adaptive;
3097
3098 a_adaptive.max_gain_db += 1.0f;
3099 EXPECT_NE(a, b);
3100 a_adaptive = b_adaptive;
3101
3102 a_adaptive.initial_gain_db += 1.0f;
3103 EXPECT_NE(a, b);
3104 a_adaptive = b_adaptive;
3105
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003106 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003107 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003108 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003109
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003110 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003111 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003112 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003113
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003114 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003115 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003116 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003117
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003118 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003119 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003120 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003121}
3122
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003123} // namespace webrtc