blob: 4d30a348f650e855ea69a7e0ec495b255ea67b4d [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 Zackrisson11b87032018-12-18 17:13:58 +0100210 apm_config.level_estimation.enabled = true;
Sam Zackrisson0824c6f2019-10-07 14:03:56 +0200211 apm_config.voice_detection.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100212 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800213 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000214}
215
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000216// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000217template <class T>
218T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200219 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000220}
221
Per Åhgren2507f8c2020-03-19 12:33:29 +0100222int16_t MaxAudioFrame(const Int16FrameData& frame) {
223 const size_t length = frame.samples_per_channel * frame.num_channels;
224 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800225 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100226 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000227 }
228
229 return max_data;
230}
231
Alex Loiko890988c2017-08-31 10:25:48 +0200232void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700233 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000234 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000235 ASSERT_TRUE(file != NULL);
236
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100237 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000238 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800239 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000240 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000241
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000242 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000243 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200244 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000245 fclose(file);
246}
247
Alex Loiko890988c2017-08-31 10:25:48 +0200248std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200249 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000250 // Resource files are all stereo.
251 ss << name << sample_rate_hz / 1000 << "_stereo";
252 return test::ResourcePath(ss.str(), "pcm");
253}
254
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000255// Temporary filenames unique to this process. Used to be able to run these
256// tests in parallel as each process needs to be running in isolation they can't
257// have competing filenames.
258std::map<std::string, std::string> temp_filenames;
259
Alex Loiko890988c2017-08-31 10:25:48 +0200260std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000261 int input_rate,
262 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700263 int reverse_input_rate,
264 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800265 size_t num_input_channels,
266 size_t num_output_channels,
267 size_t num_reverse_input_channels,
268 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700269 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200270 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700271 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
272 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000273 if (num_output_channels == 1) {
274 ss << "mono";
275 } else if (num_output_channels == 2) {
276 ss << "stereo";
277 } else {
kwiberg9e2be5f2016-09-14 05:23:22 -0700278 RTC_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000279 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700280 ss << output_rate / 1000;
281 if (num_reverse_output_channels == 1) {
282 ss << "_rmono";
283 } else if (num_reverse_output_channels == 2) {
284 ss << "_rstereo";
285 } else {
kwiberg9e2be5f2016-09-14 05:23:22 -0700286 RTC_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700287 }
288 ss << reverse_output_rate / 1000;
289 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000290
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000291 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700292 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000293 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
294 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000295}
296
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000297void ClearTempFiles() {
298 for (auto& kv : temp_filenames)
299 remove(kv.second.c_str());
300}
301
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200302// Only remove "out" files. Keep "ref" files.
303void ClearTempOutFiles() {
304 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
305 const std::string& filename = it->first;
306 if (filename.substr(0, 3).compare("out") == 0) {
307 remove(it->second.c_str());
308 temp_filenames.erase(it++);
309 } else {
310 it++;
311 }
312 }
313}
314
Alex Loiko890988c2017-08-31 10:25:48 +0200315void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000316 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000317 ASSERT_TRUE(file != NULL);
318 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000319 fclose(file);
320}
321
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000322// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
323// stereo) file, converts to deinterleaved float (optionally downmixing) and
324// returns the result in |cb|. Returns false if the file ended (or on error) and
325// true otherwise.
326//
327// |int_data| and |float_data| are just temporary space that must be
328// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200329bool ReadChunk(FILE* file,
330 int16_t* int_data,
331 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000332 ChannelBuffer<float>* cb) {
333 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000334 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000335 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
336 if (read_count != frame_size) {
337 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700338 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000339 return false; // This is expected.
340 }
341
342 S16ToFloat(int_data, frame_size, float_data);
343 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000344 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000345 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200346 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000347 }
348
349 return true;
350}
351
Per Åhgrena43178c2020-09-25 12:02:32 +0200352// Returns the reference file name that matches the current CPU
353// architecture/optimizations.
354std::string GetReferenceFilename() {
355#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
356 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
357#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
358 if (GetCPUInfo(kAVX2) != 0) {
359 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
360 }
361 return test::ResourcePath("audio_processing/output_data_float", "pb");
362#endif
363}
364
niklase@google.com470e71d2011-07-07 08:21:25 +0000365class ApmTest : public ::testing::Test {
366 protected:
367 ApmTest();
368 virtual void SetUp();
369 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000370
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200371 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000372
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200373 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000374
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000375 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200376 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000377
378 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000379 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000380 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800381 size_t num_input_channels,
382 size_t num_output_channels,
383 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000384 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000385 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000386 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100387 bool ReadFrame(FILE* file, Int16FrameData* frame);
388 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
389 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200390 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100391 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000392 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200393 void ProcessDelayVerificationTest(int delay_ms,
394 int system_delay_ms,
395 int delay_min,
396 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700397 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800398 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700399 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800400 void TestChangingForwardChannels(size_t num_in_channels,
401 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700402 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800403 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700404 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000405 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
406 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000407 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000408 int ProcessStreamChooser(Format format);
409 int AnalyzeReverseStreamChooser(Format format);
410 void ProcessDebugDump(const std::string& in_filename,
411 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800412 Format format,
413 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000414 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000415
416 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000417 const std::string ref_filename_;
kwiberg62eaacf2016-02-17 06:39:05 -0800418 std::unique_ptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100419 Int16FrameData frame_;
420 Int16FrameData revframe_;
kwiberg62eaacf2016-02-17 06:39:05 -0800421 std::unique_ptr<ChannelBuffer<float> > float_cb_;
422 std::unique_ptr<ChannelBuffer<float> > revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000423 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800424 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000425 FILE* far_file_;
426 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000427 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000428};
429
430ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000431 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200432 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000433 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000434 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000435 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000436 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000437 out_file_(NULL) {
Per Åhgrencc73ed32020-04-26 23:56:17 +0200438 apm_.reset(AudioProcessingBuilderForTesting().Create());
Per Åhgrenc0424252019-12-10 13:04:15 +0100439 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100440 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100441 apm_config.pipeline.maximum_internal_processing_rate = 48000;
442 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000443}
niklase@google.com470e71d2011-07-07 08:21:25 +0000444
445void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000446 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000447
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000448 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000449}
450
451void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000452 if (far_file_) {
453 ASSERT_EQ(0, fclose(far_file_));
454 }
455 far_file_ = NULL;
456
457 if (near_file_) {
458 ASSERT_EQ(0, fclose(near_file_));
459 }
460 near_file_ = NULL;
461
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000462 if (out_file_) {
463 ASSERT_EQ(0, fclose(out_file_));
464 }
465 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000466}
467
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000468void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200469 ASSERT_EQ(
470 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100471 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200472 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100473 {revframe_.sample_rate_hz, revframe_.num_channels},
474 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000475}
476
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000477void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000478 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000479 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800480 size_t num_input_channels,
481 size_t num_output_channels,
482 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000483 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200484 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000485 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000486 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000487
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200488 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000489 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000490 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000491
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000492 if (far_file_) {
493 ASSERT_EQ(0, fclose(far_file_));
494 }
495 std::string filename = ResourceFilePath("far", sample_rate_hz);
496 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200497 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000498
499 if (near_file_) {
500 ASSERT_EQ(0, fclose(near_file_));
501 }
502 filename = ResourceFilePath("near", sample_rate_hz);
503 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200504 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000505
506 if (open_output_file) {
507 if (out_file_) {
508 ASSERT_EQ(0, fclose(out_file_));
509 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700510 filename = OutputFilePath(
511 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
512 reverse_sample_rate_hz, num_input_channels, num_output_channels,
513 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000514 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200515 ASSERT_TRUE(out_file_ != NULL)
516 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000517 }
518}
519
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000520void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000521 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000522}
523
Jonas Olssona4d87372019-07-05 19:08:33 +0200524bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100525 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000526 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000527 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100528 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200529 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100530 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000531 if (read_count != frame_size) {
532 // Check that the file really ended.
533 EXPECT_NE(0, feof(file));
534 return false; // This is expected.
535 }
536
Per Åhgren2507f8c2020-03-19 12:33:29 +0100537 if (frame->num_channels == 1) {
538 MixStereoToMono(frame->data.data(), frame->data.data(),
539 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000540 }
541
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000542 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000543 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000544 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000545 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000546}
547
Per Åhgren2507f8c2020-03-19 12:33:29 +0100548bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000549 return ReadFrame(file, frame, NULL);
550}
551
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000552// If the end of the file has been reached, rewind it and attempt to read the
553// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200554void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100555 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000556 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200557 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000558 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200559 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000560 }
561}
562
Per Åhgren2507f8c2020-03-19 12:33:29 +0100563void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000564 ReadFrameWithRewind(file, frame, NULL);
565}
566
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000567int ApmTest::ProcessStreamChooser(Format format) {
568 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100569 return apm_->ProcessStream(
570 frame_.data.data(),
571 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
572 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100573 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000574 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200575 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100576 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100577 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100578 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200579 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000580}
581
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000582int ApmTest::AnalyzeReverseStreamChooser(Format format) {
583 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100584 return apm_->ProcessReverseStream(
585 revframe_.data.data(),
586 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
587 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
588 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000589 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000590 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100591 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100592 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000593}
594
Jonas Olssona4d87372019-07-05 19:08:33 +0200595void ApmTest::ProcessDelayVerificationTest(int delay_ms,
596 int system_delay_ms,
597 int delay_min,
598 int delay_max) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000599 // The |revframe_| and |frame_| should include the proper frame information,
600 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100601 Int16FrameData tmp_frame;
602 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000603 bool causal = true;
604
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200605 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000606 SetFrameTo(&tmp_frame, 0);
607
608 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
609 // Initialize the |frame_queue| with empty frames.
610 int frame_delay = delay_ms / 10;
611 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100612 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000613 frame->CopyFrom(tmp_frame);
614 frame_queue.push(frame);
615 frame_delay++;
616 causal = false;
617 }
618 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100619 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000620 frame->CopyFrom(tmp_frame);
621 frame_queue.push(frame);
622 frame_delay--;
623 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000624 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
625 // need enough frames with audio to have reliable estimates, but as few as
626 // possible to keep processing time down. 4.5 seconds seemed to be a good
627 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000628 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100629 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000630 frame->CopyFrom(tmp_frame);
631 // Use the near end recording, since that has more speech in it.
632 ASSERT_TRUE(ReadFrame(near_file_, frame));
633 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100634 Int16FrameData* reverse_frame = frame;
635 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000636 if (!causal) {
637 reverse_frame = frame_queue.front();
638 // When we call ProcessStream() the frame is modified, so we can't use the
639 // pointer directly when things are non-causal. Use an intermediate frame
640 // and copy the data.
641 process_frame = &tmp_frame;
642 process_frame->CopyFrom(*frame);
643 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100644 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
645 reverse_frame->data.data(),
646 StreamConfig(reverse_frame->sample_rate_hz,
647 reverse_frame->num_channels),
648 StreamConfig(reverse_frame->sample_rate_hz,
649 reverse_frame->num_channels),
650 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000651 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100652 EXPECT_EQ(apm_->kNoError,
653 apm_->ProcessStream(process_frame->data.data(),
654 StreamConfig(process_frame->sample_rate_hz,
655 process_frame->num_channels),
656 StreamConfig(process_frame->sample_rate_hz,
657 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100658 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000659 frame = frame_queue.front();
660 frame_queue.pop();
661 delete frame;
662
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000663 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000664 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100665 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000666 }
667 }
668
669 rewind(near_file_);
670 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100671 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000672 frame_queue.pop();
673 delete frame;
674 }
675 // Calculate expected delay estimate and acceptable regions. Further,
676 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700677 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100678 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700679 const int expected_median =
680 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
681 const int expected_median_high = rtc::SafeClamp<int>(
682 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700683 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700684 const int expected_median_low = rtc::SafeClamp<int>(
685 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700686 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000687 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100688 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200689 ASSERT_TRUE(stats.delay_median_ms.has_value());
690 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000691 EXPECT_GE(expected_median_high, median);
692 EXPECT_LE(expected_median_low, median);
693}
694
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000695void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000696 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000697 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000698
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000699 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200700 AudioProcessing::Config apm_config = apm_->GetConfig();
701 apm_config.gain_controller1.enabled = true;
702 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200703 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000704
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000705 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200706 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000707 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200708 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000709
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000710 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200711 apm_config.echo_canceller.enabled = true;
712 apm_config.echo_canceller.mobile_mode = false;
713 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000714 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200715 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200716 apm_config.gain_controller1.enabled = false;
717 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000718
719 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000720 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100721 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000722
723 // Resets after successful ProcessStream().
724 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000725 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100726 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000727
728 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200729 apm_config.gain_controller1.enabled = true;
730 apm_->ApplyConfig(apm_config);
731 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100732 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200733 apm_config.gain_controller1.enabled = false;
734 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000735
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000736 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200737 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100738 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000739
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000740 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000741 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200742 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000743 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000744}
745
746TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000747 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000748}
749
750TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000751 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000752}
753
Michael Graczyk86c6d332015-07-23 11:41:39 -0700754void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800755 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700756 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100757 frame_.num_channels = num_channels;
758
759 EXPECT_EQ(expected_return,
760 apm_->ProcessStream(
761 frame_.data.data(),
762 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
763 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100764 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100765 EXPECT_EQ(expected_return,
766 apm_->ProcessReverseStream(
767 frame_.data.data(),
768 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
769 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
770 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000771}
772
Michael Graczyk86c6d332015-07-23 11:41:39 -0700773void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800774 size_t num_in_channels,
775 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700776 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100777 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700778 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
779
780 EXPECT_EQ(expected_return,
781 apm_->ProcessStream(float_cb_->channels(), input_stream,
782 output_stream, float_cb_->channels()));
783}
784
785void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800786 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700787 AudioProcessing::Error expected_return) {
788 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100789 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700790 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100791 {frame_.sample_rate_hz, num_rev_channels},
792 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700793
ekmeyerson60d9b332015-08-14 10:35:55 -0700794 EXPECT_EQ(
795 expected_return,
796 apm_->ProcessReverseStream(
797 float_cb_->channels(), processing_config.reverse_input_stream(),
798 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700799}
800
801TEST_F(ApmTest, ChannelsInt16Interface) {
802 // Testing number of invalid and valid channels.
803 Init(16000, 16000, 16000, 4, 4, 4, false);
804
805 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
806
Peter Kasting69558702016-01-12 16:26:35 -0800807 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700808 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000809 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000810 }
811}
812
Michael Graczyk86c6d332015-07-23 11:41:39 -0700813TEST_F(ApmTest, Channels) {
814 // Testing number of invalid and valid channels.
815 Init(16000, 16000, 16000, 4, 4, 4, false);
816
817 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
818 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
819
Peter Kasting69558702016-01-12 16:26:35 -0800820 for (size_t i = 1; i < 4; ++i) {
821 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700822 // Output channels much be one or match input channels.
823 if (j == 1 || i == j) {
824 TestChangingForwardChannels(i, j, kNoErr);
825 TestChangingReverseChannels(i, kNoErr);
826
827 EXPECT_EQ(i, apm_->num_input_channels());
828 EXPECT_EQ(j, apm_->num_output_channels());
829 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800830 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700831 } else {
832 TestChangingForwardChannels(i, j,
833 AudioProcessing::kBadNumberChannelsError);
834 }
835 }
836 }
837}
838
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000839TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100840 // Testing some valid sample rates.
841 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
842 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000843 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000844 }
845}
846
Sam Zackrissone277bde2019-10-25 10:07:54 +0200847// This test repeatedly reconfigures the pre-amplifier in APM, processes a
848// number of frames, and checks that output signal has the right level.
849TEST_F(ApmTest, PreAmplifier) {
850 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200851 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100852 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200853 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100854 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200855 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
856 }
857 }
858 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100859 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200860 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200861
Per Åhgren2507f8c2020-03-19 12:33:29 +0100862 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200863 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
864 return std::accumulate(data.begin(), data.end(), 0.0f,
865 [](float a, float b) { return a + b * b; }) /
866 data.size() / 32768 / 32768;
867 };
868
869 const float input_power = compute_power(tmp_frame);
870 // Double-check that the input data is large compared to the error kEpsilon.
871 constexpr float kEpsilon = 1e-4f;
872 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
873
874 // 1. Enable pre-amp with 0 dB gain.
875 AudioProcessing::Config config = apm_->GetConfig();
876 config.pre_amplifier.enabled = true;
877 config.pre_amplifier.fixed_gain_factor = 1.0f;
878 apm_->ApplyConfig(config);
879
880 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200881 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200882 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
883 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200884 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200885 EXPECT_NEAR(output_power, input_power, kEpsilon);
886 config = apm_->GetConfig();
887 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
888
889 // 2. Change pre-amp gain via ApplyConfig.
890 config.pre_amplifier.fixed_gain_factor = 2.0f;
891 apm_->ApplyConfig(config);
892
893 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200894 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200895 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
896 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200897 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200898 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
899 config = apm_->GetConfig();
900 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
901
902 // 3. Change pre-amp gain via a RuntimeSetting.
903 apm_->SetRuntimeSetting(
904 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
905
906 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200907 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200908 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
909 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200910 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200911 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
912 config = apm_->GetConfig();
913 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
914}
915
Per Åhgrendb5d7282021-03-15 16:31:04 +0000916// This test a simple test that ensures that the emulated analog mic gain
917// functionality runs without crashing.
918TEST_F(ApmTest, AnalogMicGainEmulation) {
919 // Fill the audio frame with a sawtooth pattern.
920 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
921 const size_t samples_per_channel = frame_.samples_per_channel;
922 for (size_t i = 0; i < samples_per_channel; i++) {
923 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
924 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
925 }
926 }
927 // Cache the frame in tmp_frame.
928 Int16FrameData tmp_frame;
929 tmp_frame.CopyFrom(frame_);
930
931 // Enable the analog gain emulation.
932 AudioProcessing::Config config = apm_->GetConfig();
933 config.capture_level_adjustment.enabled = true;
934 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
935 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
936 config.gain_controller1.enabled = true;
937 config.gain_controller1.mode =
938 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
939 config.gain_controller1.analog_gain_controller.enabled = true;
940 apm_->ApplyConfig(config);
941
942 // Process a number of frames to ensure that the code runs without crashes.
943 for (int i = 0; i < 20; ++i) {
944 frame_.CopyFrom(tmp_frame);
945 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
946 }
947}
948
949// This test repeatedly reconfigures the capture level adjustment functionality
950// in APM, processes a number of frames, and checks that output signal has the
951// right level.
952TEST_F(ApmTest, CaptureLevelAdjustment) {
953 // Fill the audio frame with a sawtooth pattern.
954 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
955 const size_t samples_per_channel = frame_.samples_per_channel;
956 for (size_t i = 0; i < samples_per_channel; i++) {
957 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
958 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
959 }
960 }
961 // Cache the frame in tmp_frame.
962 Int16FrameData tmp_frame;
963 tmp_frame.CopyFrom(frame_);
964
965 auto compute_power = [](const Int16FrameData& frame) {
966 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
967 return std::accumulate(data.begin(), data.end(), 0.0f,
968 [](float a, float b) { return a + b * b; }) /
969 data.size() / 32768 / 32768;
970 };
971
972 const float input_power = compute_power(tmp_frame);
973 // Double-check that the input data is large compared to the error kEpsilon.
974 constexpr float kEpsilon = 1e-20f;
975 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
976
977 // 1. Enable pre-amp with 0 dB gain.
978 AudioProcessing::Config config = apm_->GetConfig();
979 config.capture_level_adjustment.enabled = true;
980 config.capture_level_adjustment.pre_gain_factor = 0.5f;
981 config.capture_level_adjustment.post_gain_factor = 4.f;
982 const float expected_output_power1 =
983 config.capture_level_adjustment.pre_gain_factor *
984 config.capture_level_adjustment.pre_gain_factor *
985 config.capture_level_adjustment.post_gain_factor *
986 config.capture_level_adjustment.post_gain_factor * input_power;
987 apm_->ApplyConfig(config);
988
989 for (int i = 0; i < 20; ++i) {
990 frame_.CopyFrom(tmp_frame);
991 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
992 }
993 float output_power = compute_power(frame_);
994 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
995 config = apm_->GetConfig();
996 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
997 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
998
999 // 2. Change pre-amp gain via ApplyConfig.
1000 config.capture_level_adjustment.pre_gain_factor = 1.0f;
1001 config.capture_level_adjustment.post_gain_factor = 2.f;
1002 const float expected_output_power2 =
1003 config.capture_level_adjustment.pre_gain_factor *
1004 config.capture_level_adjustment.pre_gain_factor *
1005 config.capture_level_adjustment.post_gain_factor *
1006 config.capture_level_adjustment.post_gain_factor * input_power;
1007 apm_->ApplyConfig(config);
1008
1009 for (int i = 0; i < 20; ++i) {
1010 frame_.CopyFrom(tmp_frame);
1011 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1012 }
1013 output_power = compute_power(frame_);
1014 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1015 config = apm_->GetConfig();
1016 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1017 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1018
1019 // 3. Change pre-amp gain via a RuntimeSetting.
1020 constexpr float kPreGain3 = 0.5f;
1021 constexpr float kPostGain3 = 3.f;
1022 const float expected_output_power3 =
1023 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1024
1025 apm_->SetRuntimeSetting(
1026 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1027 apm_->SetRuntimeSetting(
1028 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1029
1030 for (int i = 0; i < 20; ++i) {
1031 frame_.CopyFrom(tmp_frame);
1032 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1033 }
1034 output_power = compute_power(frame_);
1035 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1036 config = apm_->GetConfig();
1037 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1038 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1039}
1040
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001041TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001042 AudioProcessing::Config config = apm_->GetConfig();
1043 config.gain_controller1.enabled = false;
1044 apm_->ApplyConfig(config);
1045 config.gain_controller1.enabled = true;
1046 apm_->ApplyConfig(config);
1047
niklase@google.com470e71d2011-07-07 08:21:25 +00001048 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001049 for (auto mode :
1050 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1051 AudioProcessing::Config::GainController1::kFixedDigital,
1052 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1053 config.gain_controller1.mode = mode;
1054 apm_->ApplyConfig(config);
1055 apm_->set_stream_analog_level(100);
1056 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001057 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001058
Sam Zackrisson41478c72019-10-15 10:10:26 +02001059 // Testing target levels
1060 for (int target_level_dbfs : {0, 15, 31}) {
1061 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1062 apm_->ApplyConfig(config);
1063 apm_->set_stream_analog_level(100);
1064 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001065 }
1066
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001067 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001068 for (int compression_gain_db : {0, 10, 90}) {
1069 config.gain_controller1.compression_gain_db = compression_gain_db;
1070 apm_->ApplyConfig(config);
1071 apm_->set_stream_analog_level(100);
1072 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001073 }
1074
1075 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001076 for (bool enable : {false, true}) {
1077 config.gain_controller1.enable_limiter = enable;
1078 apm_->ApplyConfig(config);
1079 apm_->set_stream_analog_level(100);
1080 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1081 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001082
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001083 // Testing level limits
Sam Zackrisson41478c72019-10-15 10:10:26 +02001084 std::array<int, 4> kMinLevels = {0, 0, 255, 65000};
1085 std::array<int, 4> kMaxLevels = {255, 1024, 65535, 65535};
1086 for (size_t i = 0; i < kMinLevels.size(); ++i) {
1087 int min_level = kMinLevels[i];
1088 int max_level = kMaxLevels[i];
1089 config.gain_controller1.analog_level_minimum = min_level;
1090 config.gain_controller1.analog_level_maximum = max_level;
1091 apm_->ApplyConfig(config);
1092 apm_->set_stream_analog_level((min_level + max_level) / 2);
1093 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001094 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001095}
1096
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001097#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001098using ApmDeathTest = ApmTest;
1099
1100TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001101 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001102 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001103 config.gain_controller1.target_level_dbfs = -1;
1104 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001105}
1106
Tommia5e07cc2020-05-26 21:40:37 +02001107TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001108 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001109 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001110 config.gain_controller1.target_level_dbfs = 32;
1111 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001112}
1113
Tommia5e07cc2020-05-26 21:40:37 +02001114TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001115 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001116 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001117 config.gain_controller1.compression_gain_db = -1;
1118 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001119}
1120
Tommia5e07cc2020-05-26 21:40:37 +02001121TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001122 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001123 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001124 config.gain_controller1.compression_gain_db = 91;
1125 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001126}
1127
Tommia5e07cc2020-05-26 21:40:37 +02001128TEST_F(ApmDeathTest, GainControlDiesOnTooLowAnalogLevelLowerLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001129 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001130 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001131 config.gain_controller1.analog_level_minimum = -1;
1132 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001133}
1134
Tommia5e07cc2020-05-26 21:40:37 +02001135TEST_F(ApmDeathTest, GainControlDiesOnTooHighAnalogLevelUpperLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001136 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001137 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001138 config.gain_controller1.analog_level_maximum = 65536;
1139 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001140}
1141
Tommia5e07cc2020-05-26 21:40:37 +02001142TEST_F(ApmDeathTest, GainControlDiesOnInvertedAnalogLevelLimits) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001143 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001144 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001145 config.gain_controller1.analog_level_minimum = 512;
1146 config.gain_controller1.analog_level_maximum = 255;
1147 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001148}
1149
Tommia5e07cc2020-05-26 21:40:37 +02001150TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001151 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001152 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001153 config.gain_controller1.analog_level_minimum = 255;
1154 config.gain_controller1.analog_level_maximum = 512;
1155 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001156 EXPECT_DEATH(apm_->set_stream_analog_level(254), "");
1157}
1158
Tommia5e07cc2020-05-26 21:40:37 +02001159TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001160 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001161 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001162 config.gain_controller1.analog_level_minimum = 255;
1163 config.gain_controller1.analog_level_maximum = 512;
1164 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001165 EXPECT_DEATH(apm_->set_stream_analog_level(513), "");
1166}
1167#endif
1168
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001169void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001170 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001171 auto config = apm_->GetConfig();
1172 config.gain_controller1.enabled = true;
1173 config.gain_controller1.mode =
1174 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1175 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001176
1177 int out_analog_level = 0;
1178 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001179 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001180 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001181 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001182
1183 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001184 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001185 EXPECT_EQ(apm_->kNoError,
1186 apm_->ProcessStream(
1187 frame_.data.data(),
1188 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1189 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001190 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001191 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001192 }
1193
1194 // Ensure the AGC is still able to reach the maximum.
1195 EXPECT_EQ(255, out_analog_level);
1196}
1197
1198// Verifies that despite volume slider quantization, the AGC can continue to
1199// increase its volume.
1200TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001201 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001202 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1203 }
1204}
1205
1206void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001207 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001208 auto config = apm_->GetConfig();
1209 config.gain_controller1.enabled = true;
1210 config.gain_controller1.mode =
1211 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1212 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001213
1214 int out_analog_level = 100;
1215 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001216 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001217 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001218 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001219
Sam Zackrisson41478c72019-10-15 10:10:26 +02001220 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001221 EXPECT_EQ(apm_->kNoError,
1222 apm_->ProcessStream(
1223 frame_.data.data(),
1224 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1225 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001226 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001227 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001228 }
1229
1230 // Ensure the volume was raised.
1231 EXPECT_GT(out_analog_level, 100);
1232 int highest_level_reached = out_analog_level;
1233 // Simulate a user manual volume change.
1234 out_analog_level = 100;
1235
1236 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001237 ReadFrameWithRewind(near_file_, &frame_);
1238 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001239
Sam Zackrisson41478c72019-10-15 10:10:26 +02001240 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001241 EXPECT_EQ(apm_->kNoError,
1242 apm_->ProcessStream(
1243 frame_.data.data(),
1244 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1245 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001246 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001247 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001248 // Check that AGC respected the manually adjusted volume.
1249 EXPECT_LT(out_analog_level, highest_level_reached);
1250 }
1251 // Check that the volume was still raised.
1252 EXPECT_GT(out_analog_level, 100);
1253}
1254
1255TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001256 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001257 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1258 }
1259}
1260
niklase@google.com470e71d2011-07-07 08:21:25 +00001261TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001262 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001263 AudioProcessing::Config apm_config;
1264 apm_config.high_pass_filter.enabled = true;
1265 apm_->ApplyConfig(apm_config);
1266 apm_config.high_pass_filter.enabled = false;
1267 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001268}
1269
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001270TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001271 AudioProcessing::Config config = apm_->GetConfig();
1272 EXPECT_FALSE(config.echo_canceller.enabled);
1273 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001274 EXPECT_FALSE(config.gain_controller1.enabled);
Sam Zackrisson11b87032018-12-18 17:13:58 +01001275 EXPECT_FALSE(config.level_estimation.enabled);
saza0bad15f2019-10-16 11:46:11 +02001276 EXPECT_FALSE(config.noise_suppression.enabled);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001277 EXPECT_FALSE(config.voice_detection.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001278}
1279
1280TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001281 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001282 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001283 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001284 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001285 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001286 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001287 EXPECT_EQ(apm_->kNoError,
1288 apm_->ProcessStream(
1289 frame_.data.data(),
1290 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1291 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001292 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001293 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001294 EXPECT_EQ(apm_->kNoError,
1295 apm_->ProcessReverseStream(
1296 frame_.data.data(),
1297 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1298 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1299 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001300 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001301 }
1302 }
1303}
1304
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001305TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1306 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001307 const size_t kSamples = 160;
1308 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001309 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001310 float dest[kSamples] = {};
1311
1312 auto src_channels = &src[0];
1313 auto dest_channels = &dest[0];
1314
Per Åhgrencc73ed32020-04-26 23:56:17 +02001315 apm_.reset(AudioProcessingBuilderForTesting().Create());
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001316 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1317 StreamConfig(sample_rate, 1),
1318 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001319
1320 for (size_t i = 0; i < kSamples; ++i) {
1321 EXPECT_EQ(src[i], dest[i]);
1322 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001323
1324 // Same for ProcessReverseStream.
1325 float rev_dest[kSamples] = {};
1326 auto rev_dest_channels = &rev_dest[0];
1327
1328 StreamConfig input_stream = {sample_rate, 1};
1329 StreamConfig output_stream = {sample_rate, 1};
1330 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1331 output_stream, &rev_dest_channels));
1332
1333 for (size_t i = 0; i < kSamples; ++i) {
1334 EXPECT_EQ(src[i], rev_dest[i]);
1335 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001336}
1337
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001338TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1339 EnableAllComponents();
1340
pkasting25702cb2016-01-08 13:50:27 -08001341 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001342 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1343 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001344 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001345 ASSERT_EQ(0, feof(far_file_));
1346 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001347 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001348 CopyLeftToRightChannel(revframe_.data.data(),
1349 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001350
Per Åhgren2507f8c2020-03-19 12:33:29 +01001351 ASSERT_EQ(
1352 kNoErr,
1353 apm_->ProcessReverseStream(
1354 revframe_.data.data(),
1355 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1356 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1357 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001358
Per Åhgren2507f8c2020-03-19 12:33:29 +01001359 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001360
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001361 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001362 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001363 ASSERT_EQ(kNoErr,
1364 apm_->ProcessStream(
1365 frame_.data.data(),
1366 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1367 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001368 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001369 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001370
Per Åhgren2507f8c2020-03-19 12:33:29 +01001371 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001372 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001373 rewind(far_file_);
1374 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001375 }
1376}
1377
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001378TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001379 // Verify the filter is not active through undistorted audio when:
1380 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001381 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001382 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001383 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001384 EXPECT_EQ(apm_->kNoError,
1385 apm_->ProcessStream(
1386 frame_.data.data(),
1387 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1388 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001389 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001390 EXPECT_EQ(apm_->kNoError,
1391 apm_->ProcessStream(
1392 frame_.data.data(),
1393 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1394 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001395 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001396 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001397
1398 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001399 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001400 SetFrameTo(&frame_, 1000);
1401 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001402 apm_config.level_estimation.enabled = true;
1403 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001404 EXPECT_EQ(apm_->kNoError,
1405 apm_->ProcessStream(
1406 frame_.data.data(),
1407 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1408 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001409 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001410 EXPECT_EQ(apm_->kNoError,
1411 apm_->ProcessStream(
1412 frame_.data.data(),
1413 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1414 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001415 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001416 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001417 apm_config.level_estimation.enabled = false;
1418 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001419
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001420 // 3. Only GetStatistics-reporting VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001421 SetFrameTo(&frame_, 1000);
1422 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001423 apm_config.voice_detection.enabled = true;
1424 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001425 EXPECT_EQ(apm_->kNoError,
1426 apm_->ProcessStream(
1427 frame_.data.data(),
1428 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1429 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001430 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001431 EXPECT_EQ(apm_->kNoError,
1432 apm_->ProcessStream(
1433 frame_.data.data(),
1434 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1435 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001436 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001437 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001438 apm_config.voice_detection.enabled = false;
1439 apm_->ApplyConfig(apm_config);
1440
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001441 // 4. Both the VAD and the level estimator are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001442 SetFrameTo(&frame_, 1000);
1443 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001444 apm_config.voice_detection.enabled = true;
saza6787f232019-10-11 19:31:07 +02001445 apm_config.level_estimation.enabled = true;
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001446 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001447 EXPECT_EQ(apm_->kNoError,
1448 apm_->ProcessStream(
1449 frame_.data.data(),
1450 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1451 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001452 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001453 EXPECT_EQ(apm_->kNoError,
1454 apm_->ProcessStream(
1455 frame_.data.data(),
1456 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1457 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001458 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001459 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001460 apm_config.voice_detection.enabled = false;
saza6787f232019-10-11 19:31:07 +02001461 apm_config.level_estimation.enabled = false;
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001462 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001463
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001464 // Check the test is valid. We should have distortion from the filter
1465 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001466 apm_config.echo_canceller.enabled = true;
1467 apm_config.echo_canceller.mobile_mode = false;
1468 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001469 frame_.samples_per_channel = 320;
1470 frame_.num_channels = 2;
1471 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001472 SetFrameTo(&frame_, 1000);
1473 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001474 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001475 EXPECT_EQ(apm_->kNoError,
1476 apm_->ProcessStream(
1477 frame_.data.data(),
1478 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1479 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001480 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001481 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001482}
1483
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001484#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1485void ApmTest::ProcessDebugDump(const std::string& in_filename,
1486 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001487 Format format,
1488 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001489 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001490 FILE* in_file = fopen(in_filename.c_str(), "rb");
1491 ASSERT_TRUE(in_file != NULL);
1492 audioproc::Event event_msg;
1493 bool first_init = true;
1494
1495 while (ReadMessageFromFile(in_file, &event_msg)) {
1496 if (event_msg.type() == audioproc::Event::INIT) {
1497 const audioproc::Init msg = event_msg.init();
1498 int reverse_sample_rate = msg.sample_rate();
1499 if (msg.has_reverse_sample_rate()) {
1500 reverse_sample_rate = msg.reverse_sample_rate();
1501 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001502 int output_sample_rate = msg.sample_rate();
1503 if (msg.has_output_sample_rate()) {
1504 output_sample_rate = msg.output_sample_rate();
1505 }
1506
Jonas Olssona4d87372019-07-05 19:08:33 +02001507 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1508 msg.num_input_channels(), msg.num_output_channels(),
1509 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001510 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001511 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001512 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001513 auto aec_dump =
1514 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1515 EXPECT_TRUE(aec_dump);
1516 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001517 first_init = false;
1518 }
1519
1520 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1521 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1522
1523 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001524 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001525 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001526 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001527 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1528 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001529 }
1530 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001531 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001532 if (format == kFloatFormat) {
1533 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001534 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001535 }
1536 }
1537 AnalyzeReverseStreamChooser(format);
1538
1539 } else if (event_msg.type() == audioproc::Event::STREAM) {
1540 const audioproc::Stream msg = event_msg.stream();
1541 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001542 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001543
Sam Zackrisson41478c72019-10-15 10:10:26 +02001544 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001545 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001546 if (msg.has_keypress()) {
1547 apm_->set_stream_key_pressed(msg.keypress());
1548 } else {
1549 apm_->set_stream_key_pressed(true);
1550 }
1551
1552 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001553 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001554 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001555 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001556 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1557 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001558 }
1559 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001560 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001561 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001562 if (format == kFloatFormat) {
1563 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001564 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001565 }
1566 }
1567 ProcessStreamChooser(format);
1568 }
1569 }
aleloif4dd1912017-06-15 01:55:38 -07001570 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001571 fclose(in_file);
1572}
1573
1574void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001575 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001576 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001577 std::string format_string;
1578 switch (format) {
1579 case kIntFormat:
1580 format_string = "_int";
1581 break;
1582 case kFloatFormat:
1583 format_string = "_float";
1584 break;
1585 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001586 const std::string ref_filename = test::TempFilename(
1587 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1588 const std::string out_filename = test::TempFilename(
1589 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001590 const std::string limited_filename = test::TempFilename(
1591 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1592 const size_t logging_limit_bytes = 100000;
1593 // We expect at least this many bytes in the created logfile.
1594 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001595 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001596 ProcessDebugDump(in_filename, ref_filename, format, -1);
1597 ProcessDebugDump(ref_filename, out_filename, format, -1);
1598 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001599
1600 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1601 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001602 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001603 ASSERT_TRUE(ref_file != NULL);
1604 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001605 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001606 std::unique_ptr<uint8_t[]> ref_bytes;
1607 std::unique_ptr<uint8_t[]> out_bytes;
1608 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001609
1610 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1611 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001612 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001613 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001614 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001615 while (ref_size > 0 && out_size > 0) {
1616 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001617 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001618 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001619 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001620 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001621 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001622 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1623 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001624 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001625 }
1626 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001627 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1628 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001629 EXPECT_NE(0, feof(ref_file));
1630 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001631 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001632 ASSERT_EQ(0, fclose(ref_file));
1633 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001634 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001635 remove(ref_filename.c_str());
1636 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001637 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001638}
1639
pbosc7a65692016-05-06 12:50:04 -07001640TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001641 VerifyDebugDumpTest(kIntFormat);
1642}
1643
pbosc7a65692016-05-06 12:50:04 -07001644TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001645 VerifyDebugDumpTest(kFloatFormat);
1646}
1647#endif
1648
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001649// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001650TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001651 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001652 const std::string filename =
1653 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001654 {
1655 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1656 EXPECT_FALSE(aec_dump);
1657 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001658
1659#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1660 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001661 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001662
aleloif4dd1912017-06-15 01:55:38 -07001663 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1664 EXPECT_TRUE(aec_dump);
1665 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001666 EXPECT_EQ(apm_->kNoError,
1667 apm_->ProcessStream(
1668 frame_.data.data(),
1669 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1670 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001671 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001672 EXPECT_EQ(apm_->kNoError,
1673 apm_->ProcessReverseStream(
1674 revframe_.data.data(),
1675 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1676 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1677 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001678 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001679
1680 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001681 FILE* fid = fopen(filename.c_str(), "r");
1682 ASSERT_TRUE(fid != NULL);
1683
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001684 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001685 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001686 ASSERT_EQ(0, remove(filename.c_str()));
1687#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001688 // Verify the file has NOT been written.
1689 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1690#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1691}
1692
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001693// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001694TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001695 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001696
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001697 const std::string filename =
1698 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001699 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1700 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001701
1702#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1703 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001704 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001705
Niels Möllere8e4dc42019-06-11 14:04:16 +02001706 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001707 EXPECT_TRUE(aec_dump);
1708 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001709 EXPECT_EQ(apm_->kNoError,
1710 apm_->ProcessReverseStream(
1711 revframe_.data.data(),
1712 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1713 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1714 revframe_.data.data()));
1715 EXPECT_EQ(apm_->kNoError,
1716 apm_->ProcessStream(
1717 frame_.data.data(),
1718 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1719 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001720 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001721 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001722
1723 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001724 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001725 ASSERT_TRUE(fid != NULL);
1726
1727 // Clean it up.
1728 ASSERT_EQ(0, fclose(fid));
1729 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001730#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1731}
1732
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001733// TODO(andrew): Add a test to process a few frames with different combinations
1734// of enabled components.
1735
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001736TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001737 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001738 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001739
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001740 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001741 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001742 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001743 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001744 for (size_t i = 0; i < arraysize(kChannels); i++) {
1745 for (size_t j = 0; j < arraysize(kChannels); j++) {
1746 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001747 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001748 test->set_num_reverse_channels(kChannels[i]);
1749 test->set_num_input_channels(kChannels[j]);
1750 test->set_num_output_channels(kChannels[j]);
1751 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001752 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001753 }
1754 }
1755 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001756#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1757 // To test the extended filter mode.
1758 audioproc::Test* test = ref_data.add_test();
1759 test->set_num_reverse_channels(2);
1760 test->set_num_input_channels(2);
1761 test->set_num_output_channels(2);
1762 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1763 test->set_use_aec_extended_filter(true);
1764#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001765 }
1766
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001767 for (int i = 0; i < ref_data.test_size(); i++) {
1768 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001769
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001770 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001771 // TODO(ajm): We no longer allow different input and output channels. Skip
1772 // these tests for now, but they should be removed from the set.
1773 if (test->num_input_channels() != test->num_output_channels())
1774 continue;
1775
Per Åhgrencc73ed32020-04-26 23:56:17 +02001776 apm_.reset(AudioProcessingBuilderForTesting().Create());
Per Åhgren0695df12020-01-13 14:43:13 +01001777 AudioProcessing::Config apm_config = apm_->GetConfig();
1778 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1779 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001780
1781 EnableAllComponents();
1782
Jonas Olssona4d87372019-07-05 19:08:33 +02001783 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001784 static_cast<size_t>(test->num_input_channels()),
1785 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001786 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001787
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001788 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001789 int has_voice_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001790 int analog_level = 127;
1791 int analog_level_average = 0;
1792 int max_output_average = 0;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001793 float rms_dbfs_average = 0.0f;
minyue58530ed2016-05-24 05:50:12 -07001794#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001795 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001796#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001797
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001798 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001799 EXPECT_EQ(
1800 apm_->kNoError,
1801 apm_->ProcessReverseStream(
1802 revframe_.data.data(),
1803 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1804 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1805 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001806
1807 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001808 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001809
Per Åhgren2507f8c2020-03-19 12:33:29 +01001810 EXPECT_EQ(apm_->kNoError,
1811 apm_->ProcessStream(
1812 frame_.data.data(),
1813 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1814 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001815 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001816
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001817 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001818 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001819 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001820
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001821 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001822
Sam Zackrisson41478c72019-10-15 10:10:26 +02001823 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001824 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001825 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001826 EXPECT_TRUE(stats.voice_detected);
1827 EXPECT_TRUE(stats.output_rms_dbfs);
1828 has_voice_count += *stats.voice_detected ? 1 : 0;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001829 rms_dbfs_average += *stats.output_rms_dbfs;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001830
Per Åhgren2507f8c2020-03-19 12:33:29 +01001831 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001832 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001833 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001834 ASSERT_EQ(frame_size, write_count);
1835
1836 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001837 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001838 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001839
1840#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1841 const int kStatsAggregationFrameNum = 100; // 1 second.
1842 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001843 // Get echo and delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +01001844 AudioProcessingStats stats = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001845
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001846 // Echo metrics.
1847 const float echo_return_loss = stats.echo_return_loss.value_or(-1.0f);
1848 const float echo_return_loss_enhancement =
1849 stats.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001850 const float residual_echo_likelihood =
1851 stats.residual_echo_likelihood.value_or(-1.0f);
1852 const float residual_echo_likelihood_recent_max =
1853 stats.residual_echo_likelihood_recent_max.value_or(-1.0f);
1854
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001855 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001856 const audioproc::Test::EchoMetrics& reference =
1857 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001858 constexpr float kEpsilon = 0.01;
1859 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1860 EXPECT_NEAR(echo_return_loss_enhancement,
1861 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001862 EXPECT_NEAR(residual_echo_likelihood,
1863 reference.residual_echo_likelihood(), kEpsilon);
1864 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1865 reference.residual_echo_likelihood_recent_max(),
1866 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001867 ++stats_index;
1868 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001869 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1870 message_echo->set_echo_return_loss(echo_return_loss);
1871 message_echo->set_echo_return_loss_enhancement(
1872 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001873 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1874 message_echo->set_residual_echo_likelihood_recent_max(
1875 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001876 }
1877 }
1878#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001879 }
1880 max_output_average /= frame_count;
1881 analog_level_average /= frame_count;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001882 rms_dbfs_average /= frame_count;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001883
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001884 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001885 const int kIntNear = 1;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001886 // When running the test on a N7 we get a {2, 6} difference of
1887 // |has_voice_count| and |max_output_average| is up to 18 higher.
1888 // All numbers being consistently higher on N7 compare to ref_data.
1889 // TODO(bjornv): If we start getting more of these offsets on Android we
1890 // should consider a different approach. Either using one slack for all,
1891 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001892#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001893 const int kHasVoiceCountOffset = 3;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001894 const int kHasVoiceCountNear = 8;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001895 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001896 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001897#else
1898 const int kHasVoiceCountOffset = 0;
1899 const int kHasVoiceCountNear = kIntNear;
1900 const int kMaxOutputAverageOffset = 0;
1901 const int kMaxOutputAverageNear = kIntNear;
1902#endif
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001903 EXPECT_NEAR(test->has_voice_count(),
Jonas Olssona4d87372019-07-05 19:08:33 +02001904 has_voice_count - kHasVoiceCountOffset, kHasVoiceCountNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001905
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001906 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001907 EXPECT_NEAR(test->max_output_average(),
1908 max_output_average - kMaxOutputAverageOffset,
1909 kMaxOutputAverageNear);
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001910#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Per Åhgrena43178c2020-09-25 12:02:32 +02001911 const double kFloatNear = 0.002;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001912 EXPECT_NEAR(test->rms_dbfs_average(), rms_dbfs_average, kFloatNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001913#endif
1914 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001915 test->set_has_voice_count(has_voice_count);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001916
1917 test->set_analog_level_average(analog_level_average);
1918 test->set_max_output_average(max_output_average);
1919
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001920#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrisson11b87032018-12-18 17:13:58 +01001921 test->set_rms_dbfs_average(rms_dbfs_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001922#endif
1923 }
1924
1925 rewind(far_file_);
1926 rewind(near_file_);
1927 }
1928
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001929 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001930 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001931 }
1932}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001933
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001934TEST_F(ApmTest, NoErrorsWithKeyboardChannel) {
1935 struct ChannelFormat {
1936 AudioProcessing::ChannelLayout in_layout;
1937 AudioProcessing::ChannelLayout out_layout;
1938 };
1939 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02001940 {AudioProcessing::kMonoAndKeyboard, AudioProcessing::kMono},
1941 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kMono},
1942 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kStereo},
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001943 };
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001944
Per Åhgrencc73ed32020-04-26 23:56:17 +02001945 std::unique_ptr<AudioProcessing> ap(
1946 AudioProcessingBuilderForTesting().Create());
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001947 // Enable one component just to ensure some processing takes place.
saza0bad15f2019-10-16 11:46:11 +02001948 AudioProcessing::Config config;
1949 config.noise_suppression.enabled = true;
1950 ap->ApplyConfig(config);
pkasting25702cb2016-01-08 13:50:27 -08001951 for (size_t i = 0; i < arraysize(cf); ++i) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001952 const int in_rate = 44100;
1953 const int out_rate = 48000;
1954 ChannelBuffer<float> in_cb(SamplesFromRate(in_rate),
1955 TotalChannelsFromLayout(cf[i].in_layout));
1956 ChannelBuffer<float> out_cb(SamplesFromRate(out_rate),
1957 ChannelsFromLayout(cf[i].out_layout));
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001958 bool has_keyboard = cf[i].in_layout == AudioProcessing::kMonoAndKeyboard ||
1959 cf[i].in_layout == AudioProcessing::kStereoAndKeyboard;
1960 StreamConfig in_sc(in_rate, ChannelsFromLayout(cf[i].in_layout),
1961 has_keyboard);
1962 StreamConfig out_sc(out_rate, ChannelsFromLayout(cf[i].out_layout));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001963
1964 // Run over a few chunks.
1965 for (int j = 0; j < 10; ++j) {
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001966 EXPECT_NOERR(ap->ProcessStream(in_cb.channels(), in_sc, out_sc,
1967 out_cb.channels()));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001968 }
1969 }
1970}
1971
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001972// Compares the reference and test arrays over a region around the expected
1973// delay. Finds the highest SNR in that region and adds the variance and squared
1974// error results to the supplied accumulators.
1975void UpdateBestSNR(const float* ref,
1976 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001977 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001978 int expected_delay,
1979 double* variance_acc,
1980 double* sq_error_acc) {
1981 double best_snr = std::numeric_limits<double>::min();
1982 double best_variance = 0;
1983 double best_sq_error = 0;
1984 // Search over a region of eight samples around the expected delay.
1985 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1986 ++delay) {
1987 double sq_error = 0;
1988 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001989 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001990 double error = test[i + delay] - ref[i];
1991 sq_error += error * error;
1992 variance += ref[i] * ref[i];
1993 }
1994
1995 if (sq_error == 0) {
1996 *variance_acc += variance;
1997 return;
1998 }
1999 double snr = variance / sq_error;
2000 if (snr > best_snr) {
2001 best_snr = snr;
2002 best_variance = variance;
2003 best_sq_error = sq_error;
2004 }
2005 }
2006
2007 *variance_acc += best_variance;
2008 *sq_error_acc += best_sq_error;
2009}
2010
2011// Used to test a multitude of sample rate and channel combinations. It works
2012// by first producing a set of reference files (in SetUpTestCase) that are
2013// assumed to be correct, as the used parameters are verified by other tests
2014// in this collection. Primarily the reference files are all produced at
2015// "native" rates which do not involve any resampling.
2016
2017// Each test pass produces an output file with a particular format. The output
2018// is matched against the reference file closest to its internal processing
2019// format. If necessary the output is resampled back to its process format.
2020// Due to the resampling distortion, we don't expect identical results, but
2021// enforce SNR thresholds which vary depending on the format. 0 is a special
2022// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02002023typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002024class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002025 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002026 public:
2027 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02002028 : input_rate_(std::get<0>(GetParam())),
2029 output_rate_(std::get<1>(GetParam())),
2030 reverse_input_rate_(std::get<2>(GetParam())),
2031 reverse_output_rate_(std::get<3>(GetParam())),
2032 expected_snr_(std::get<4>(GetParam())),
2033 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002034
2035 virtual ~AudioProcessingTest() {}
2036
Mirko Bonadei71061bc2019-06-04 09:01:51 +02002037 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002038 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07002039 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08002040 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08002041 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
2042 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
2043 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002044 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07002045 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
2046 kNativeRates[i], kNumChannels[j], kNumChannels[j],
2047 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002048 }
2049 }
2050 }
2051 }
2052
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02002053 void TearDown() {
2054 // Remove "out" files after each test.
2055 ClearTempOutFiles();
2056 }
2057
Mirko Bonadei71061bc2019-06-04 09:01:51 +02002058 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07002059
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002060 // Runs a process pass on files with the given parameters and dumps the output
ekmeyerson60d9b332015-08-14 10:35:55 -07002061 // to a file specified with |output_file_prefix|. Both forward and reverse
2062 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002063 static void ProcessFormat(int input_rate,
2064 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07002065 int reverse_input_rate,
2066 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08002067 size_t num_input_channels,
2068 size_t num_output_channels,
2069 size_t num_reverse_input_channels,
2070 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02002071 const std::string& output_file_prefix) {
Per Åhgrencc73ed32020-04-26 23:56:17 +02002072 std::unique_ptr<AudioProcessing> ap(
2073 AudioProcessingBuilderForTesting().Create());
Per Åhgren0695df12020-01-13 14:43:13 +01002074 AudioProcessing::Config apm_config = ap->GetConfig();
2075 apm_config.gain_controller1.analog_gain_controller.enabled = false;
2076 ap->ApplyConfig(apm_config);
2077
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002078 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002079
ekmeyerson60d9b332015-08-14 10:35:55 -07002080 ProcessingConfig processing_config = {
2081 {{input_rate, num_input_channels},
2082 {output_rate, num_output_channels},
2083 {reverse_input_rate, num_reverse_input_channels},
2084 {reverse_output_rate, num_reverse_output_channels}}};
2085 ap->Initialize(processing_config);
2086
2087 FILE* far_file =
2088 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002089 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02002090 FILE* out_file = fopen(
2091 OutputFilePath(
2092 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2093 reverse_output_rate, num_input_channels, num_output_channels,
2094 num_reverse_input_channels, num_reverse_output_channels, kForward)
2095 .c_str(),
2096 "wb");
2097 FILE* rev_out_file = fopen(
2098 OutputFilePath(
2099 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2100 reverse_output_rate, num_input_channels, num_output_channels,
2101 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2102 .c_str(),
2103 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002104 ASSERT_TRUE(far_file != NULL);
2105 ASSERT_TRUE(near_file != NULL);
2106 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07002107 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002108
2109 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
2110 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002111 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
2112 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002113 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
2114 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07002115 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
2116 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002117
2118 // Temporary buffers.
2119 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07002120 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2121 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08002122 std::unique_ptr<float[]> float_data(new float[max_length]);
2123 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002124
2125 int analog_level = 127;
2126 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2127 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002128 EXPECT_NOERR(ap->ProcessReverseStream(
2129 rev_cb.channels(), processing_config.reverse_input_stream(),
2130 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002131
2132 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002133 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002134
2135 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002136 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2137 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002138
ekmeyerson60d9b332015-08-14 10:35:55 -07002139 // Dump forward output to file.
2140 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002141 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002142 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002143
Jonas Olssona4d87372019-07-05 19:08:33 +02002144 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2145 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002146
ekmeyerson60d9b332015-08-14 10:35:55 -07002147 // Dump reverse output to file.
2148 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2149 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002150 size_t rev_out_length =
2151 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002152
Jonas Olssona4d87372019-07-05 19:08:33 +02002153 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2154 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002155
Sam Zackrisson41478c72019-10-15 10:10:26 +02002156 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002157 }
2158 fclose(far_file);
2159 fclose(near_file);
2160 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002161 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002162 }
2163
2164 protected:
2165 int input_rate_;
2166 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002167 int reverse_input_rate_;
2168 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002169 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002170 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002171};
2172
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002173TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002174 struct ChannelFormat {
2175 int num_input;
2176 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002177 int num_reverse_input;
2178 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002179 };
2180 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002181 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2182 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002183 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002184
pkasting25702cb2016-01-08 13:50:27 -08002185 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002186 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2187 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2188 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002189
ekmeyerson60d9b332015-08-14 10:35:55 -07002190 // Verify output for both directions.
2191 std::vector<StreamDirection> stream_directions;
2192 stream_directions.push_back(kForward);
2193 stream_directions.push_back(kReverse);
2194 for (StreamDirection file_direction : stream_directions) {
2195 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2196 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2197 const int out_num =
2198 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2199 const double expected_snr =
2200 file_direction ? expected_reverse_snr_ : expected_snr_;
2201
2202 const int min_ref_rate = std::min(in_rate, out_rate);
2203 int ref_rate;
2204
2205 if (min_ref_rate > 32000) {
2206 ref_rate = 48000;
2207 } else if (min_ref_rate > 16000) {
2208 ref_rate = 32000;
2209 } else if (min_ref_rate > 8000) {
2210 ref_rate = 16000;
2211 } else {
2212 ref_rate = 8000;
2213 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002214
ekmeyerson60d9b332015-08-14 10:35:55 -07002215 FILE* out_file = fopen(
2216 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2217 reverse_output_rate_, cf[i].num_input,
2218 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002219 cf[i].num_reverse_output, file_direction)
2220 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002221 "rb");
2222 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002223 FILE* ref_file =
2224 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2225 cf[i].num_output, cf[i].num_output,
2226 cf[i].num_reverse_output,
2227 cf[i].num_reverse_output, file_direction)
2228 .c_str(),
2229 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002230 ASSERT_TRUE(out_file != NULL);
2231 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002232
pkasting25702cb2016-01-08 13:50:27 -08002233 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2234 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002235 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002236 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002237 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002238 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002239 // Data from the resampled output, in case the reference and output rates
2240 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002241 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002242
ekmeyerson60d9b332015-08-14 10:35:55 -07002243 PushResampler<float> resampler;
2244 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002245
ekmeyerson60d9b332015-08-14 10:35:55 -07002246 // Compute the resampling delay of the output relative to the reference,
2247 // to find the region over which we should search for the best SNR.
2248 float expected_delay_sec = 0;
2249 if (in_rate != ref_rate) {
2250 // Input resampling delay.
2251 expected_delay_sec +=
2252 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2253 }
2254 if (out_rate != ref_rate) {
2255 // Output resampling delay.
2256 expected_delay_sec +=
2257 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2258 // Delay of converting the output back to its processing rate for
2259 // testing.
2260 expected_delay_sec +=
2261 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2262 }
2263 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002264 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002265
ekmeyerson60d9b332015-08-14 10:35:55 -07002266 double variance = 0;
2267 double sq_error = 0;
2268 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2269 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2270 float* out_ptr = out_data.get();
2271 if (out_rate != ref_rate) {
2272 // Resample the output back to its internal processing rate if
2273 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002274 ASSERT_EQ(ref_length,
2275 static_cast<size_t>(resampler.Resample(
2276 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002277 out_ptr = cmp_data.get();
2278 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002279
ekmeyerson60d9b332015-08-14 10:35:55 -07002280 // Update the |sq_error| and |variance| accumulators with the highest
2281 // SNR of reference vs output.
2282 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2283 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002284 }
2285
ekmeyerson60d9b332015-08-14 10:35:55 -07002286 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2287 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2288 << cf[i].num_input << ", " << cf[i].num_output << ", "
2289 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2290 << ", " << file_direction << "): ";
2291 if (sq_error > 0) {
2292 double snr = 10 * log10(variance / sq_error);
2293 EXPECT_GE(snr, expected_snr);
2294 EXPECT_NE(0, expected_snr);
2295 std::cout << "SNR=" << snr << " dB" << std::endl;
2296 } else {
aluebs776593b2016-03-15 14:04:58 -07002297 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002298 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002299
ekmeyerson60d9b332015-08-14 10:35:55 -07002300 fclose(out_file);
2301 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002302 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002303 }
2304}
2305
2306#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002307INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002308 CommonFormats,
2309 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002310 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2311 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2312 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2313 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2314 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2315 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2316 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2317 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2318 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2319 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2320 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2321 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002322
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002323 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2324 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2325 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2326 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2327 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2328 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2329 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2330 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2331 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2332 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2333 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2334 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002335
Per Åhgrenc0424252019-12-10 13:04:15 +01002336 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2337 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2338 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002339 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2340 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2341 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2342 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2343 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002344 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002345 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2346 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2347 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002348
Per Åhgrenc0424252019-12-10 13:04:15 +01002349 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2350 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2351 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002352 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2353 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2354 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2355 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2356 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2357 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2358 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002359 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002360 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002361
2362#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002363INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002364 CommonFormats,
2365 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002366 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2367 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2368 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002369 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2370 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2371 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002372 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2373 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2374 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002375 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2376 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2377 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002378
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002379 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2380 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2381 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2382 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2383 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2384 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002385 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2386 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2387 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2388 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2389 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2390 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002391
Per Åhgrenc0424252019-12-10 13:04:15 +01002392 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2393 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2394 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002395 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2396 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2397 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002398 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002399 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002400 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002401 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2402 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2403 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002404
Per Åhgrenc0424252019-12-10 13:04:15 +01002405 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2406 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2407 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002408 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2409 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2410 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002411 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002412 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002413 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002414 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2415 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002416 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002417#endif
2418
Per Åhgren3e8bf282019-08-29 23:38:40 +02002419// Produces a scoped trace debug output.
2420std::string ProduceDebugText(int render_input_sample_rate_hz,
2421 int render_output_sample_rate_hz,
2422 int capture_input_sample_rate_hz,
2423 int capture_output_sample_rate_hz,
2424 size_t render_input_num_channels,
2425 size_t render_output_num_channels,
2426 size_t capture_input_num_channels,
2427 size_t capture_output_num_channels) {
2428 rtc::StringBuilder ss;
2429 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002430 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002431 << render_input_sample_rate_hz
2432 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002433 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002434 << render_output_sample_rate_hz
2435 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002436 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002437 << capture_input_sample_rate_hz
2438 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002439 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002440 << capture_output_sample_rate_hz
2441 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002442 "\nNumber of channels:"
2443 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002444 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002445 << "\n Render output: " << render_output_num_channels
2446 << "\n Capture input: " << capture_input_num_channels
2447 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002448 return ss.Release();
2449}
2450
2451// Validates that running the audio processing module using various combinations
2452// of sample rates and number of channels works as intended.
2453void RunApmRateAndChannelTest(
2454 rtc::ArrayView<const int> sample_rates_hz,
2455 rtc::ArrayView<const int> render_channel_counts,
2456 rtc::ArrayView<const int> capture_channel_counts) {
Per Åhgrencc73ed32020-04-26 23:56:17 +02002457 std::unique_ptr<AudioProcessing> apm(
2458 AudioProcessingBuilderForTesting().Create());
Per Åhgren3e8bf282019-08-29 23:38:40 +02002459 webrtc::AudioProcessing::Config apm_config;
2460 apm_config.echo_canceller.enabled = true;
2461 apm->ApplyConfig(apm_config);
2462
2463 StreamConfig render_input_stream_config;
2464 StreamConfig render_output_stream_config;
2465 StreamConfig capture_input_stream_config;
2466 StreamConfig capture_output_stream_config;
2467
2468 std::vector<float> render_input_frame_channels;
2469 std::vector<float*> render_input_frame;
2470 std::vector<float> render_output_frame_channels;
2471 std::vector<float*> render_output_frame;
2472 std::vector<float> capture_input_frame_channels;
2473 std::vector<float*> capture_input_frame;
2474 std::vector<float> capture_output_frame_channels;
2475 std::vector<float*> capture_output_frame;
2476
2477 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2478 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2479 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2480 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2481 for (size_t render_input_num_channels : render_channel_counts) {
2482 for (size_t capture_input_num_channels : capture_channel_counts) {
2483 size_t render_output_num_channels = render_input_num_channels;
2484 size_t capture_output_num_channels = capture_input_num_channels;
2485 auto populate_audio_frame = [](int sample_rate_hz,
2486 size_t num_channels,
2487 StreamConfig* cfg,
2488 std::vector<float>* channels_data,
2489 std::vector<float*>* frame_data) {
2490 cfg->set_sample_rate_hz(sample_rate_hz);
2491 cfg->set_num_channels(num_channels);
2492 cfg->set_has_keyboard(false);
2493
2494 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2495 channels_data->resize(num_channels * max_frame_size);
2496 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2497 frame_data->resize(num_channels);
2498 for (size_t channel = 0; channel < num_channels; ++channel) {
2499 (*frame_data)[channel] =
2500 &(*channels_data)[channel * max_frame_size];
2501 }
2502 };
2503
2504 populate_audio_frame(
2505 render_input_sample_rate_hz, render_input_num_channels,
2506 &render_input_stream_config, &render_input_frame_channels,
2507 &render_input_frame);
2508 populate_audio_frame(
2509 render_output_sample_rate_hz, render_output_num_channels,
2510 &render_output_stream_config, &render_output_frame_channels,
2511 &render_output_frame);
2512 populate_audio_frame(
2513 capture_input_sample_rate_hz, capture_input_num_channels,
2514 &capture_input_stream_config, &capture_input_frame_channels,
2515 &capture_input_frame);
2516 populate_audio_frame(
2517 capture_output_sample_rate_hz, capture_output_num_channels,
2518 &capture_output_stream_config, &capture_output_frame_channels,
2519 &capture_output_frame);
2520
2521 for (size_t frame = 0; frame < 2; ++frame) {
2522 SCOPED_TRACE(ProduceDebugText(
2523 render_input_sample_rate_hz, render_output_sample_rate_hz,
2524 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2525 render_input_num_channels, render_output_num_channels,
2526 render_input_num_channels, capture_output_num_channels));
2527
2528 int result = apm->ProcessReverseStream(
2529 &render_input_frame[0], render_input_stream_config,
2530 render_output_stream_config, &render_output_frame[0]);
2531 EXPECT_EQ(result, AudioProcessing::kNoError);
2532 result = apm->ProcessStream(
2533 &capture_input_frame[0], capture_input_stream_config,
2534 capture_output_stream_config, &capture_output_frame[0]);
2535 EXPECT_EQ(result, AudioProcessing::kNoError);
2536 }
2537 }
2538 }
2539 }
2540 }
2541 }
2542 }
2543}
2544
Alessio Bazzica3438a932020-10-14 12:47:50 +02002545constexpr void Toggle(bool& b) {
2546 b ^= true;
2547}
2548
niklase@google.com470e71d2011-07-07 08:21:25 +00002549} // namespace
peahc19f3122016-10-07 14:54:10 -07002550
Alessio Bazzicac054e782018-04-16 12:10:09 +02002551TEST(RuntimeSettingTest, TestDefaultCtor) {
2552 auto s = AudioProcessing::RuntimeSetting();
2553 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2554}
2555
Alessio Bazzicac054e782018-04-16 12:10:09 +02002556TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2557 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2558 auto s = AudioProcessing::RuntimeSetting();
2559 ASSERT_TRUE(q.Insert(&s));
2560 ASSERT_TRUE(q.Remove(&s));
2561 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2562}
2563
Sam Zackrisson0beac582017-09-25 12:04:02 +02002564TEST(ApmConfiguration, EnablePostProcessing) {
2565 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002566 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002567 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002568 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002569 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002570 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002571 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002572 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002573 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002574
Per Åhgren2507f8c2020-03-19 12:33:29 +01002575 Int16FrameData audio;
2576 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002577 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2578
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002579 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002580 apm->ProcessStream(audio.data.data(),
2581 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2582 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002583 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002584}
2585
Alex Loiko5825aa62017-12-18 16:02:40 +01002586TEST(ApmConfiguration, EnablePreProcessing) {
2587 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002588 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002589 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002590 auto mock_pre_processor =
2591 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002592 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002593 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002594 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002595 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002596
Per Åhgren2507f8c2020-03-19 12:33:29 +01002597 Int16FrameData audio;
2598 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002599 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2600
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002601 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002602 apm->ProcessReverseStream(
2603 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2604 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2605 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002606}
2607
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002608TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2609 // Verify that apm uses a capture analyzer if one is provided.
2610 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002611 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002612 auto mock_capture_analyzer =
2613 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2614 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002615 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002616 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2617 .Create();
2618
Per Åhgren2507f8c2020-03-19 12:33:29 +01002619 Int16FrameData audio;
2620 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002621 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2622
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002623 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002624 apm->ProcessStream(audio.data.data(),
2625 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2626 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002627 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002628}
2629
Alex Loiko73ec0192018-05-15 10:52:28 +02002630TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2631 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002632 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002633 auto mock_pre_processor =
2634 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2635 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002636 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002637 .SetRenderPreProcessing(std::move(mock_pre_processor))
2638 .Create();
2639 apm->SetRuntimeSetting(
2640 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2641
2642 // RuntimeSettings forwarded during 'Process*Stream' calls.
2643 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002644 Int16FrameData audio;
2645 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002646 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2647
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002648 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2649 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002650 apm->ProcessReverseStream(
2651 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2652 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2653 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002654}
2655
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002656class MyEchoControlFactory : public EchoControlFactory {
2657 public:
2658 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2659 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002660 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2661 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002662 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2663 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002664 return std::unique_ptr<EchoControl>(ec);
2665 }
Per Åhgrence202a02019-09-02 17:01:19 +02002666
2667 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002668 int num_render_channels,
2669 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002670 return Create(sample_rate_hz);
2671 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002672};
2673
2674TEST(ApmConfiguration, EchoControlInjection) {
2675 // Verify that apm uses an injected echo controller if one is provided.
2676 webrtc::Config webrtc_config;
2677 std::unique_ptr<EchoControlFactory> echo_control_factory(
2678 new MyEchoControlFactory());
2679
Alex Loiko5825aa62017-12-18 16:02:40 +01002680 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002681 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002682 .SetEchoControlFactory(std::move(echo_control_factory))
2683 .Create(webrtc_config);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002684
Per Åhgren2507f8c2020-03-19 12:33:29 +01002685 Int16FrameData audio;
2686 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002687 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002688 apm->ProcessStream(audio.data.data(),
2689 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2690 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002691 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002692 apm->ProcessReverseStream(
2693 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2694 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2695 audio.data.data());
2696 apm->ProcessStream(audio.data.data(),
2697 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2698 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002699 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002700}
Ivo Creusenae026092017-11-20 13:07:16 +01002701
Per Åhgren8607f842019-04-12 22:02:26 +02002702std::unique_ptr<AudioProcessing> CreateApm(bool mobile_aec) {
Ivo Creusenae026092017-11-20 13:07:16 +01002703 Config old_config;
Ivo Creusen62337e52018-01-09 14:17:33 +01002704 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +02002705 AudioProcessingBuilderForTesting().Create(old_config));
Ivo Creusenae026092017-11-20 13:07:16 +01002706 if (!apm) {
2707 return apm;
2708 }
2709
2710 ProcessingConfig processing_config = {
2711 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2712
2713 if (apm->Initialize(processing_config) != 0) {
2714 return nullptr;
2715 }
2716
2717 // Disable all components except for an AEC and the residual echo detector.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002718 AudioProcessing::Config apm_config;
2719 apm_config.residual_echo_detector.enabled = true;
2720 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002721 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002722 apm_config.gain_controller2.enabled = false;
2723 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002724 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002725 apm_config.noise_suppression.enabled = false;
2726 apm_config.level_estimation.enabled = false;
2727 apm_config.voice_detection.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002728 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002729 return apm;
2730}
2731
2732#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2733#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2734#else
2735#define MAYBE_ApmStatistics ApmStatistics
2736#endif
2737
Per Åhgren8607f842019-04-12 22:02:26 +02002738TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2739 // Set up APM with AEC3 and process some audio.
2740 std::unique_ptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002741 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002742 AudioProcessing::Config apm_config;
2743 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002744 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002745
2746 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002747 Int16FrameData frame;
2748 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002749 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002750
2751 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002752 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002753 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2754 ptr[i] = 10000 * ((i % 3) - 1);
2755 }
2756
2757 // Do some processing.
2758 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002759 EXPECT_EQ(apm->ProcessReverseStream(
2760 frame.data.data(),
2761 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2762 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2763 frame.data.data()),
2764 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002765 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002766 EXPECT_EQ(apm->ProcessStream(
2767 frame.data.data(),
2768 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2769 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002770 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002771 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002772 }
2773
2774 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002775 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002776 // We expect all statistics to be set and have a sensible value.
2777 ASSERT_TRUE(stats.residual_echo_likelihood);
2778 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2779 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2780 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max);
2781 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2782 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2783 ASSERT_TRUE(stats.echo_return_loss);
2784 EXPECT_NE(*stats.echo_return_loss, -100.0);
2785 ASSERT_TRUE(stats.echo_return_loss_enhancement);
2786 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002787}
2788
2789TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2790 // Set up APM with AECM and process some audio.
Per Åhgren8607f842019-04-12 22:02:26 +02002791 std::unique_ptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002792 ASSERT_TRUE(apm);
2793
2794 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002795 Int16FrameData frame;
2796 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002797 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002798
2799 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002800 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002801 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2802 ptr[i] = 10000 * ((i % 3) - 1);
2803 }
2804
2805 // Do some processing.
2806 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002807 EXPECT_EQ(apm->ProcessReverseStream(
2808 frame.data.data(),
2809 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2810 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2811 frame.data.data()),
2812 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002813 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002814 EXPECT_EQ(apm->ProcessStream(
2815 frame.data.data(),
2816 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2817 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002818 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002819 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002820 }
2821
2822 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002823 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002824 // We expect only the residual echo detector statistics to be set and have a
2825 // sensible value.
2826 EXPECT_TRUE(stats.residual_echo_likelihood);
2827 if (stats.residual_echo_likelihood) {
2828 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2829 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2830 }
2831 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max);
2832 if (stats.residual_echo_likelihood_recent_max) {
2833 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2834 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2835 }
2836 EXPECT_FALSE(stats.echo_return_loss);
2837 EXPECT_FALSE(stats.echo_return_loss_enhancement);
Ivo Creusenae026092017-11-20 13:07:16 +01002838}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002839
2840TEST(ApmStatistics, ReportOutputRmsDbfs) {
2841 ProcessingConfig processing_config = {
2842 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2843 AudioProcessing::Config config;
2844
2845 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002846 Int16FrameData frame;
2847 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002848 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002849
2850 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002851 int16_t* ptr = frame.data.data();
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002852 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2853 ptr[i] = 10000 * ((i % 3) - 1);
2854 }
2855
Per Åhgrencc73ed32020-04-26 23:56:17 +02002856 std::unique_ptr<AudioProcessing> apm(
2857 AudioProcessingBuilderForTesting().Create());
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002858 apm->Initialize(processing_config);
2859
2860 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002861 EXPECT_EQ(
2862 apm->ProcessStream(frame.data.data(),
2863 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2864 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002865 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002866 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002867 EXPECT_FALSE(apm->GetStatistics().output_rms_dbfs);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002868
2869 // If enabled, metrics should be reported.
2870 config.level_estimation.enabled = true;
2871 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002872 EXPECT_EQ(
2873 apm->ProcessStream(frame.data.data(),
2874 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2875 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002876 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002877 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002878 auto stats = apm->GetStatistics();
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002879 EXPECT_TRUE(stats.output_rms_dbfs);
2880 EXPECT_GE(*stats.output_rms_dbfs, 0);
2881
2882 // If re-disabled, the value is again not reported.
2883 config.level_estimation.enabled = false;
2884 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002885 EXPECT_EQ(
2886 apm->ProcessStream(frame.data.data(),
2887 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2888 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002889 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002890 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002891 EXPECT_FALSE(apm->GetStatistics().output_rms_dbfs);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002892}
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002893
2894TEST(ApmStatistics, ReportHasVoice) {
2895 ProcessingConfig processing_config = {
2896 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2897 AudioProcessing::Config config;
2898
2899 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002900 Int16FrameData frame;
2901 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002902 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2903
2904 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002905 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002906 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2907 ptr[i] = 10000 * ((i % 3) - 1);
2908 }
2909
Per Åhgrencc73ed32020-04-26 23:56:17 +02002910 std::unique_ptr<AudioProcessing> apm(
2911 AudioProcessingBuilderForTesting().Create());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002912 apm->Initialize(processing_config);
2913
2914 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002915 EXPECT_EQ(
2916 apm->ProcessStream(frame.data.data(),
2917 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2918 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002919 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002920 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002921 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002922
2923 // If enabled, metrics should be reported.
2924 config.voice_detection.enabled = true;
2925 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002926 EXPECT_EQ(
2927 apm->ProcessStream(frame.data.data(),
2928 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2929 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002930 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002931 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002932 auto stats = apm->GetStatistics();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002933 EXPECT_TRUE(stats.voice_detected);
2934
2935 // If re-disabled, the value is again not reported.
2936 config.voice_detection.enabled = false;
2937 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002938 EXPECT_EQ(
2939 apm->ProcessStream(frame.data.data(),
2940 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2941 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002942 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002943 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002944 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002945}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002946
2947TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2948 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2949 std::array<int, 2> render_channel_counts = {1, 7};
2950 std::array<int, 2> capture_channel_counts = {1, 7};
2951 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2952 capture_channel_counts);
2953}
2954
2955TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2956 std::array<int, 1> sample_rates_hz = {48000};
2957 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2958 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2959 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2960 capture_channel_counts);
2961}
2962
2963TEST(ApmConfiguration, HandlingOfRateCombinations) {
2964 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2965 48000, 96000, 192000, 384000};
2966 std::array<int, 1> render_channel_counts = {2};
2967 std::array<int, 1> capture_channel_counts = {2};
2968 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2969 capture_channel_counts);
2970}
2971
Yves Gerey1fce3f82019-12-05 17:45:31 +01002972TEST(ApmConfiguration, SelfAssignment) {
2973 // At some point memory sanitizer was complaining about self-assigment.
2974 // Make sure we don't regress.
2975 AudioProcessing::Config config;
2976 AudioProcessing::Config* config2 = &config;
2977 *config2 = *config2; // Workaround -Wself-assign-overloaded
2978 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2979}
2980
Alessio Bazzica3438a932020-10-14 12:47:50 +02002981TEST(AudioProcessing, GainController1ConfigEqual) {
2982 AudioProcessing::Config::GainController1 a;
2983 AudioProcessing::Config::GainController1 b;
2984 EXPECT_EQ(a, b);
2985
2986 Toggle(a.enabled);
2987 b.enabled = a.enabled;
2988 EXPECT_EQ(a, b);
2989
2990 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2991 b.mode = a.mode;
2992 EXPECT_EQ(a, b);
2993
2994 a.target_level_dbfs++;
2995 b.target_level_dbfs = a.target_level_dbfs;
2996 EXPECT_EQ(a, b);
2997
2998 a.compression_gain_db++;
2999 b.compression_gain_db = a.compression_gain_db;
3000 EXPECT_EQ(a, b);
3001
3002 Toggle(a.enable_limiter);
3003 b.enable_limiter = a.enable_limiter;
3004 EXPECT_EQ(a, b);
3005
3006 a.analog_level_minimum++;
3007 b.analog_level_minimum = a.analog_level_minimum;
3008 EXPECT_EQ(a, b);
3009
3010 a.analog_level_maximum--;
3011 b.analog_level_maximum = a.analog_level_maximum;
3012 EXPECT_EQ(a, b);
3013
3014 auto& a_analog = a.analog_gain_controller;
3015 auto& b_analog = b.analog_gain_controller;
3016
3017 Toggle(a_analog.enabled);
3018 b_analog.enabled = a_analog.enabled;
3019 EXPECT_EQ(a, b);
3020
3021 a_analog.startup_min_volume++;
3022 b_analog.startup_min_volume = a_analog.startup_min_volume;
3023 EXPECT_EQ(a, b);
3024
3025 a_analog.clipped_level_min++;
3026 b_analog.clipped_level_min = a_analog.clipped_level_min;
3027 EXPECT_EQ(a, b);
3028
Alessio Bazzica3438a932020-10-14 12:47:50 +02003029 Toggle(a_analog.enable_digital_adaptive);
3030 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
3031 EXPECT_EQ(a, b);
3032}
3033
3034// Checks that one differing parameter is sufficient to make two configs
3035// different.
3036TEST(AudioProcessing, GainController1ConfigNotEqual) {
3037 AudioProcessing::Config::GainController1 a;
3038 const AudioProcessing::Config::GainController1 b;
3039
3040 Toggle(a.enabled);
3041 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003042 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003043
3044 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
3045 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003046 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003047
3048 a.target_level_dbfs++;
3049 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003050 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003051
3052 a.compression_gain_db++;
3053 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003054 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003055
3056 Toggle(a.enable_limiter);
3057 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003058 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003059
3060 a.analog_level_minimum++;
3061 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003062 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003063
3064 a.analog_level_maximum--;
3065 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003066 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003067
3068 auto& a_analog = a.analog_gain_controller;
3069 const auto& b_analog = b.analog_gain_controller;
3070
3071 Toggle(a_analog.enabled);
3072 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003073 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003074
3075 a_analog.startup_min_volume++;
3076 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003077 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003078
3079 a_analog.clipped_level_min++;
3080 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003081 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003082
Alessio Bazzica3438a932020-10-14 12:47:50 +02003083 Toggle(a_analog.enable_digital_adaptive);
3084 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003085 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003086}
3087
3088TEST(AudioProcessing, GainController2ConfigEqual) {
3089 AudioProcessing::Config::GainController2 a;
3090 AudioProcessing::Config::GainController2 b;
3091 EXPECT_EQ(a, b);
3092
3093 Toggle(a.enabled);
3094 b.enabled = a.enabled;
3095 EXPECT_EQ(a, b);
3096
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003097 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003098 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3099 EXPECT_EQ(a, b);
3100
3101 auto& a_adaptive = a.adaptive_digital;
3102 auto& b_adaptive = b.adaptive_digital;
3103
3104 Toggle(a_adaptive.enabled);
3105 b_adaptive.enabled = a_adaptive.enabled;
3106 EXPECT_EQ(a, b);
3107
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003108 Toggle(a_adaptive.dry_run);
3109 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003110 EXPECT_EQ(a, b);
3111
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003112 a_adaptive.noise_estimator = AudioProcessing::Config::GainController2::
3113 NoiseEstimator::kStationaryNoise;
3114 b_adaptive.noise_estimator = a_adaptive.noise_estimator;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003115 EXPECT_EQ(a, b);
3116
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003117 a_adaptive.vad_reset_period_ms++;
3118 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003119 EXPECT_EQ(a, b);
3120
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003121 a_adaptive.adjacent_speech_frames_threshold++;
3122 b_adaptive.adjacent_speech_frames_threshold =
3123 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003124 EXPECT_EQ(a, b);
3125
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003126 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003127 b_adaptive.max_gain_change_db_per_second =
3128 a_adaptive.max_gain_change_db_per_second;
3129 EXPECT_EQ(a, b);
3130
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003131 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003132 b_adaptive.max_output_noise_level_dbfs =
3133 a_adaptive.max_output_noise_level_dbfs;
3134 EXPECT_EQ(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003135
3136 Toggle(a_adaptive.sse2_allowed);
3137 b_adaptive.sse2_allowed = a_adaptive.sse2_allowed;
3138 EXPECT_EQ(a, b);
3139
3140 Toggle(a_adaptive.avx2_allowed);
3141 b_adaptive.avx2_allowed = a_adaptive.avx2_allowed;
3142 EXPECT_EQ(a, b);
3143
3144 Toggle(a_adaptive.neon_allowed);
3145 b_adaptive.neon_allowed = a_adaptive.neon_allowed;
3146 EXPECT_EQ(a, b);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003147}
3148
3149// Checks that one differing parameter is sufficient to make two configs
3150// different.
3151TEST(AudioProcessing, GainController2ConfigNotEqual) {
3152 AudioProcessing::Config::GainController2 a;
3153 const AudioProcessing::Config::GainController2 b;
3154
3155 Toggle(a.enabled);
3156 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003157 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003158
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003159 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003160 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003161 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003162
3163 auto& a_adaptive = a.adaptive_digital;
3164 const auto& b_adaptive = b.adaptive_digital;
3165
3166 Toggle(a_adaptive.enabled);
3167 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003168 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003169
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003170 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003171 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003172 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003173
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003174 a_adaptive.noise_estimator = AudioProcessing::Config::GainController2::
3175 NoiseEstimator::kStationaryNoise;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003176 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003177 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003178
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003179 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003180 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003181 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003182
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003183 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003184 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003185 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003186
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003187 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003188 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003189 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003190
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003191 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003192 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003193 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003194
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003195 Toggle(a_adaptive.sse2_allowed);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003196 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003197 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003198
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003199 Toggle(a_adaptive.avx2_allowed);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003200 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003201 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003202
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003203 Toggle(a_adaptive.neon_allowed);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003204 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003205 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003206}
3207
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003208} // namespace webrtc