blob: 4c879c7e50d3e5709fcc14d8ddbf9692cb6a21f5 [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
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000916TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +0200917 AudioProcessing::Config config = apm_->GetConfig();
918 config.gain_controller1.enabled = false;
919 apm_->ApplyConfig(config);
920 config.gain_controller1.enabled = true;
921 apm_->ApplyConfig(config);
922
niklase@google.com470e71d2011-07-07 08:21:25 +0000923 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +0200924 for (auto mode :
925 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
926 AudioProcessing::Config::GainController1::kFixedDigital,
927 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
928 config.gain_controller1.mode = mode;
929 apm_->ApplyConfig(config);
930 apm_->set_stream_analog_level(100);
931 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000932 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000933
Sam Zackrisson41478c72019-10-15 10:10:26 +0200934 // Testing target levels
935 for (int target_level_dbfs : {0, 15, 31}) {
936 config.gain_controller1.target_level_dbfs = target_level_dbfs;
937 apm_->ApplyConfig(config);
938 apm_->set_stream_analog_level(100);
939 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000940 }
941
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100942 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +0200943 for (int compression_gain_db : {0, 10, 90}) {
944 config.gain_controller1.compression_gain_db = compression_gain_db;
945 apm_->ApplyConfig(config);
946 apm_->set_stream_analog_level(100);
947 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000948 }
949
950 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +0200951 for (bool enable : {false, true}) {
952 config.gain_controller1.enable_limiter = enable;
953 apm_->ApplyConfig(config);
954 apm_->set_stream_analog_level(100);
955 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
956 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000957
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100958 // Testing level limits
Sam Zackrisson41478c72019-10-15 10:10:26 +0200959 std::array<int, 4> kMinLevels = {0, 0, 255, 65000};
960 std::array<int, 4> kMaxLevels = {255, 1024, 65535, 65535};
961 for (size_t i = 0; i < kMinLevels.size(); ++i) {
962 int min_level = kMinLevels[i];
963 int max_level = kMaxLevels[i];
964 config.gain_controller1.analog_level_minimum = min_level;
965 config.gain_controller1.analog_level_maximum = max_level;
966 apm_->ApplyConfig(config);
967 apm_->set_stream_analog_level((min_level + max_level) / 2);
968 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000969 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000970}
971
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100972#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +0200973using ApmDeathTest = ApmTest;
974
975TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +0200976 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100977 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200978 config.gain_controller1.target_level_dbfs = -1;
979 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100980}
981
Tommia5e07cc2020-05-26 21:40:37 +0200982TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +0200983 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100984 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200985 config.gain_controller1.target_level_dbfs = 32;
986 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100987}
988
Tommia5e07cc2020-05-26 21:40:37 +0200989TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +0200990 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100991 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200992 config.gain_controller1.compression_gain_db = -1;
993 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100994}
995
Tommia5e07cc2020-05-26 21:40:37 +0200996TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +0200997 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100998 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200999 config.gain_controller1.compression_gain_db = 91;
1000 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001001}
1002
Tommia5e07cc2020-05-26 21:40:37 +02001003TEST_F(ApmDeathTest, GainControlDiesOnTooLowAnalogLevelLowerLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001004 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001005 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001006 config.gain_controller1.analog_level_minimum = -1;
1007 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001008}
1009
Tommia5e07cc2020-05-26 21:40:37 +02001010TEST_F(ApmDeathTest, GainControlDiesOnTooHighAnalogLevelUpperLimit) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001011 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001012 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001013 config.gain_controller1.analog_level_maximum = 65536;
1014 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001015}
1016
Tommia5e07cc2020-05-26 21:40:37 +02001017TEST_F(ApmDeathTest, GainControlDiesOnInvertedAnalogLevelLimits) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001018 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001019 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001020 config.gain_controller1.analog_level_minimum = 512;
1021 config.gain_controller1.analog_level_maximum = 255;
1022 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001023}
1024
Tommia5e07cc2020-05-26 21:40:37 +02001025TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001026 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001027 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001028 config.gain_controller1.analog_level_minimum = 255;
1029 config.gain_controller1.analog_level_maximum = 512;
1030 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001031 EXPECT_DEATH(apm_->set_stream_analog_level(254), "");
1032}
1033
Tommia5e07cc2020-05-26 21:40:37 +02001034TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001035 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001036 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001037 config.gain_controller1.analog_level_minimum = 255;
1038 config.gain_controller1.analog_level_maximum = 512;
1039 apm_->ApplyConfig(config);
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001040 EXPECT_DEATH(apm_->set_stream_analog_level(513), "");
1041}
1042#endif
1043
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001044void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001045 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001046 auto config = apm_->GetConfig();
1047 config.gain_controller1.enabled = true;
1048 config.gain_controller1.mode =
1049 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1050 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001051
1052 int out_analog_level = 0;
1053 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001054 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001055 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001056 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001057
1058 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001059 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001060 EXPECT_EQ(apm_->kNoError,
1061 apm_->ProcessStream(
1062 frame_.data.data(),
1063 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1064 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001065 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001066 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001067 }
1068
1069 // Ensure the AGC is still able to reach the maximum.
1070 EXPECT_EQ(255, out_analog_level);
1071}
1072
1073// Verifies that despite volume slider quantization, the AGC can continue to
1074// increase its volume.
1075TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001076 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001077 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1078 }
1079}
1080
1081void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001082 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001083 auto config = apm_->GetConfig();
1084 config.gain_controller1.enabled = true;
1085 config.gain_controller1.mode =
1086 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1087 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001088
1089 int out_analog_level = 100;
1090 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001091 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001092 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001093 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001094
Sam Zackrisson41478c72019-10-15 10:10:26 +02001095 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001096 EXPECT_EQ(apm_->kNoError,
1097 apm_->ProcessStream(
1098 frame_.data.data(),
1099 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1100 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001101 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001102 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001103 }
1104
1105 // Ensure the volume was raised.
1106 EXPECT_GT(out_analog_level, 100);
1107 int highest_level_reached = out_analog_level;
1108 // Simulate a user manual volume change.
1109 out_analog_level = 100;
1110
1111 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001112 ReadFrameWithRewind(near_file_, &frame_);
1113 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001114
Sam Zackrisson41478c72019-10-15 10:10:26 +02001115 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001116 EXPECT_EQ(apm_->kNoError,
1117 apm_->ProcessStream(
1118 frame_.data.data(),
1119 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1120 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001121 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001122 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001123 // Check that AGC respected the manually adjusted volume.
1124 EXPECT_LT(out_analog_level, highest_level_reached);
1125 }
1126 // Check that the volume was still raised.
1127 EXPECT_GT(out_analog_level, 100);
1128}
1129
1130TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001131 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001132 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1133 }
1134}
1135
niklase@google.com470e71d2011-07-07 08:21:25 +00001136TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001137 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001138 AudioProcessing::Config apm_config;
1139 apm_config.high_pass_filter.enabled = true;
1140 apm_->ApplyConfig(apm_config);
1141 apm_config.high_pass_filter.enabled = false;
1142 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001143}
1144
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001145TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001146 AudioProcessing::Config config = apm_->GetConfig();
1147 EXPECT_FALSE(config.echo_canceller.enabled);
1148 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001149 EXPECT_FALSE(config.gain_controller1.enabled);
Sam Zackrisson11b87032018-12-18 17:13:58 +01001150 EXPECT_FALSE(config.level_estimation.enabled);
saza0bad15f2019-10-16 11:46:11 +02001151 EXPECT_FALSE(config.noise_suppression.enabled);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001152 EXPECT_FALSE(config.voice_detection.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001153}
1154
1155TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001156 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001157 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001158 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001159 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001160 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001161 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001162 EXPECT_EQ(apm_->kNoError,
1163 apm_->ProcessStream(
1164 frame_.data.data(),
1165 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1166 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001167 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001168 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001169 EXPECT_EQ(apm_->kNoError,
1170 apm_->ProcessReverseStream(
1171 frame_.data.data(),
1172 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1173 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1174 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001175 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001176 }
1177 }
1178}
1179
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001180TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1181 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001182 const size_t kSamples = 160;
1183 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001184 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001185 float dest[kSamples] = {};
1186
1187 auto src_channels = &src[0];
1188 auto dest_channels = &dest[0];
1189
Per Åhgrencc73ed32020-04-26 23:56:17 +02001190 apm_.reset(AudioProcessingBuilderForTesting().Create());
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001191 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1192 StreamConfig(sample_rate, 1),
1193 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001194
1195 for (size_t i = 0; i < kSamples; ++i) {
1196 EXPECT_EQ(src[i], dest[i]);
1197 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001198
1199 // Same for ProcessReverseStream.
1200 float rev_dest[kSamples] = {};
1201 auto rev_dest_channels = &rev_dest[0];
1202
1203 StreamConfig input_stream = {sample_rate, 1};
1204 StreamConfig output_stream = {sample_rate, 1};
1205 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1206 output_stream, &rev_dest_channels));
1207
1208 for (size_t i = 0; i < kSamples; ++i) {
1209 EXPECT_EQ(src[i], rev_dest[i]);
1210 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001211}
1212
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001213TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1214 EnableAllComponents();
1215
pkasting25702cb2016-01-08 13:50:27 -08001216 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001217 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1218 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001219 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001220 ASSERT_EQ(0, feof(far_file_));
1221 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001222 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001223 CopyLeftToRightChannel(revframe_.data.data(),
1224 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001225
Per Åhgren2507f8c2020-03-19 12:33:29 +01001226 ASSERT_EQ(
1227 kNoErr,
1228 apm_->ProcessReverseStream(
1229 revframe_.data.data(),
1230 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1231 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1232 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001233
Per Åhgren2507f8c2020-03-19 12:33:29 +01001234 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001235
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001236 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001237 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001238 ASSERT_EQ(kNoErr,
1239 apm_->ProcessStream(
1240 frame_.data.data(),
1241 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1242 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001243 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001244 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001245
Per Åhgren2507f8c2020-03-19 12:33:29 +01001246 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001247 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001248 rewind(far_file_);
1249 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001250 }
1251}
1252
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001253TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001254 // Verify the filter is not active through undistorted audio when:
1255 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001256 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001257 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001258 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001259 EXPECT_EQ(apm_->kNoError,
1260 apm_->ProcessStream(
1261 frame_.data.data(),
1262 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1263 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001264 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001265 EXPECT_EQ(apm_->kNoError,
1266 apm_->ProcessStream(
1267 frame_.data.data(),
1268 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1269 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001270 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001271 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001272
1273 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001274 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001275 SetFrameTo(&frame_, 1000);
1276 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001277 apm_config.level_estimation.enabled = true;
1278 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001279 EXPECT_EQ(apm_->kNoError,
1280 apm_->ProcessStream(
1281 frame_.data.data(),
1282 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1283 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001284 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001285 EXPECT_EQ(apm_->kNoError,
1286 apm_->ProcessStream(
1287 frame_.data.data(),
1288 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1289 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001290 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001291 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001292 apm_config.level_estimation.enabled = false;
1293 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001294
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001295 // 3. Only GetStatistics-reporting VAD is enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001296 SetFrameTo(&frame_, 1000);
1297 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001298 apm_config.voice_detection.enabled = true;
1299 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001300 EXPECT_EQ(apm_->kNoError,
1301 apm_->ProcessStream(
1302 frame_.data.data(),
1303 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1304 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001305 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001306 EXPECT_EQ(apm_->kNoError,
1307 apm_->ProcessStream(
1308 frame_.data.data(),
1309 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1310 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001311 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001312 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001313 apm_config.voice_detection.enabled = false;
1314 apm_->ApplyConfig(apm_config);
1315
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001316 // 4. Both the VAD and the level estimator are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001317 SetFrameTo(&frame_, 1000);
1318 frame_copy.CopyFrom(frame_);
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001319 apm_config.voice_detection.enabled = true;
saza6787f232019-10-11 19:31:07 +02001320 apm_config.level_estimation.enabled = true;
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001321 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001322 EXPECT_EQ(apm_->kNoError,
1323 apm_->ProcessStream(
1324 frame_.data.data(),
1325 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1326 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001327 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001328 EXPECT_EQ(apm_->kNoError,
1329 apm_->ProcessStream(
1330 frame_.data.data(),
1331 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1332 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001333 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001334 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001335 apm_config.voice_detection.enabled = false;
saza6787f232019-10-11 19:31:07 +02001336 apm_config.level_estimation.enabled = false;
Sam Zackrisson6c330ab2019-01-04 10:35:53 +01001337 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001338
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001339 // Check the test is valid. We should have distortion from the filter
1340 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001341 apm_config.echo_canceller.enabled = true;
1342 apm_config.echo_canceller.mobile_mode = false;
1343 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001344 frame_.samples_per_channel = 320;
1345 frame_.num_channels = 2;
1346 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001347 SetFrameTo(&frame_, 1000);
1348 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001349 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001350 EXPECT_EQ(apm_->kNoError,
1351 apm_->ProcessStream(
1352 frame_.data.data(),
1353 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1354 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001355 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001356 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001357}
1358
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001359#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1360void ApmTest::ProcessDebugDump(const std::string& in_filename,
1361 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001362 Format format,
1363 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001364 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001365 FILE* in_file = fopen(in_filename.c_str(), "rb");
1366 ASSERT_TRUE(in_file != NULL);
1367 audioproc::Event event_msg;
1368 bool first_init = true;
1369
1370 while (ReadMessageFromFile(in_file, &event_msg)) {
1371 if (event_msg.type() == audioproc::Event::INIT) {
1372 const audioproc::Init msg = event_msg.init();
1373 int reverse_sample_rate = msg.sample_rate();
1374 if (msg.has_reverse_sample_rate()) {
1375 reverse_sample_rate = msg.reverse_sample_rate();
1376 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001377 int output_sample_rate = msg.sample_rate();
1378 if (msg.has_output_sample_rate()) {
1379 output_sample_rate = msg.output_sample_rate();
1380 }
1381
Jonas Olssona4d87372019-07-05 19:08:33 +02001382 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1383 msg.num_input_channels(), msg.num_output_channels(),
1384 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001385 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001386 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001387 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001388 auto aec_dump =
1389 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1390 EXPECT_TRUE(aec_dump);
1391 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001392 first_init = false;
1393 }
1394
1395 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1396 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1397
1398 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001399 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001400 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001401 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001402 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1403 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001404 }
1405 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001406 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001407 if (format == kFloatFormat) {
1408 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001409 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001410 }
1411 }
1412 AnalyzeReverseStreamChooser(format);
1413
1414 } else if (event_msg.type() == audioproc::Event::STREAM) {
1415 const audioproc::Stream msg = event_msg.stream();
1416 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001417 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001418
Sam Zackrisson41478c72019-10-15 10:10:26 +02001419 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001420 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001421 if (msg.has_keypress()) {
1422 apm_->set_stream_key_pressed(msg.keypress());
1423 } else {
1424 apm_->set_stream_key_pressed(true);
1425 }
1426
1427 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001428 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001429 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001430 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001431 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1432 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001433 }
1434 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001435 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001436 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001437 if (format == kFloatFormat) {
1438 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001439 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001440 }
1441 }
1442 ProcessStreamChooser(format);
1443 }
1444 }
aleloif4dd1912017-06-15 01:55:38 -07001445 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001446 fclose(in_file);
1447}
1448
1449void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001450 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001451 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001452 std::string format_string;
1453 switch (format) {
1454 case kIntFormat:
1455 format_string = "_int";
1456 break;
1457 case kFloatFormat:
1458 format_string = "_float";
1459 break;
1460 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001461 const std::string ref_filename = test::TempFilename(
1462 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1463 const std::string out_filename = test::TempFilename(
1464 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001465 const std::string limited_filename = test::TempFilename(
1466 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1467 const size_t logging_limit_bytes = 100000;
1468 // We expect at least this many bytes in the created logfile.
1469 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001470 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001471 ProcessDebugDump(in_filename, ref_filename, format, -1);
1472 ProcessDebugDump(ref_filename, out_filename, format, -1);
1473 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001474
1475 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1476 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001477 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001478 ASSERT_TRUE(ref_file != NULL);
1479 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001480 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001481 std::unique_ptr<uint8_t[]> ref_bytes;
1482 std::unique_ptr<uint8_t[]> out_bytes;
1483 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001484
1485 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1486 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001487 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001488 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001489 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001490 while (ref_size > 0 && out_size > 0) {
1491 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001492 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001493 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001494 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001495 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001496 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001497 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1498 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001499 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001500 }
1501 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001502 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1503 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001504 EXPECT_NE(0, feof(ref_file));
1505 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001506 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001507 ASSERT_EQ(0, fclose(ref_file));
1508 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001509 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001510 remove(ref_filename.c_str());
1511 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001512 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001513}
1514
pbosc7a65692016-05-06 12:50:04 -07001515TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001516 VerifyDebugDumpTest(kIntFormat);
1517}
1518
pbosc7a65692016-05-06 12:50:04 -07001519TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001520 VerifyDebugDumpTest(kFloatFormat);
1521}
1522#endif
1523
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001524// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001525TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001526 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001527 const std::string filename =
1528 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001529 {
1530 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1531 EXPECT_FALSE(aec_dump);
1532 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001533
1534#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1535 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001536 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001537
aleloif4dd1912017-06-15 01:55:38 -07001538 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1539 EXPECT_TRUE(aec_dump);
1540 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001541 EXPECT_EQ(apm_->kNoError,
1542 apm_->ProcessStream(
1543 frame_.data.data(),
1544 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1545 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001546 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001547 EXPECT_EQ(apm_->kNoError,
1548 apm_->ProcessReverseStream(
1549 revframe_.data.data(),
1550 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1551 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1552 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001553 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001554
1555 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001556 FILE* fid = fopen(filename.c_str(), "r");
1557 ASSERT_TRUE(fid != NULL);
1558
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001559 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001560 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001561 ASSERT_EQ(0, remove(filename.c_str()));
1562#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001563 // Verify the file has NOT been written.
1564 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1565#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1566}
1567
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001568// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001569TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001570 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001571
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001572 const std::string filename =
1573 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001574 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1575 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001576
1577#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1578 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001579 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001580
Niels Möllere8e4dc42019-06-11 14:04:16 +02001581 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001582 EXPECT_TRUE(aec_dump);
1583 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001584 EXPECT_EQ(apm_->kNoError,
1585 apm_->ProcessReverseStream(
1586 revframe_.data.data(),
1587 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1588 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1589 revframe_.data.data()));
1590 EXPECT_EQ(apm_->kNoError,
1591 apm_->ProcessStream(
1592 frame_.data.data(),
1593 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1594 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001595 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001596 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001597
1598 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001599 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001600 ASSERT_TRUE(fid != NULL);
1601
1602 // Clean it up.
1603 ASSERT_EQ(0, fclose(fid));
1604 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001605#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1606}
1607
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001608// TODO(andrew): Add a test to process a few frames with different combinations
1609// of enabled components.
1610
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001611TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001612 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001613 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001614
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001615 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001616 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001617 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001618 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001619 for (size_t i = 0; i < arraysize(kChannels); i++) {
1620 for (size_t j = 0; j < arraysize(kChannels); j++) {
1621 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001622 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001623 test->set_num_reverse_channels(kChannels[i]);
1624 test->set_num_input_channels(kChannels[j]);
1625 test->set_num_output_channels(kChannels[j]);
1626 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001627 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001628 }
1629 }
1630 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001631#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1632 // To test the extended filter mode.
1633 audioproc::Test* test = ref_data.add_test();
1634 test->set_num_reverse_channels(2);
1635 test->set_num_input_channels(2);
1636 test->set_num_output_channels(2);
1637 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1638 test->set_use_aec_extended_filter(true);
1639#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001640 }
1641
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001642 for (int i = 0; i < ref_data.test_size(); i++) {
1643 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001644
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001645 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001646 // TODO(ajm): We no longer allow different input and output channels. Skip
1647 // these tests for now, but they should be removed from the set.
1648 if (test->num_input_channels() != test->num_output_channels())
1649 continue;
1650
Per Åhgrencc73ed32020-04-26 23:56:17 +02001651 apm_.reset(AudioProcessingBuilderForTesting().Create());
Per Åhgren0695df12020-01-13 14:43:13 +01001652 AudioProcessing::Config apm_config = apm_->GetConfig();
1653 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1654 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001655
1656 EnableAllComponents();
1657
Jonas Olssona4d87372019-07-05 19:08:33 +02001658 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001659 static_cast<size_t>(test->num_input_channels()),
1660 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001661 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001662
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001663 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001664 int has_voice_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001665 int analog_level = 127;
1666 int analog_level_average = 0;
1667 int max_output_average = 0;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001668 float rms_dbfs_average = 0.0f;
minyue58530ed2016-05-24 05:50:12 -07001669#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001670 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001671#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001672
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001673 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001674 EXPECT_EQ(
1675 apm_->kNoError,
1676 apm_->ProcessReverseStream(
1677 revframe_.data.data(),
1678 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1679 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1680 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001681
1682 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001683 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001684
Per Åhgren2507f8c2020-03-19 12:33:29 +01001685 EXPECT_EQ(apm_->kNoError,
1686 apm_->ProcessStream(
1687 frame_.data.data(),
1688 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1689 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001690 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001691
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001692 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001693 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001694 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001695
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001696 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001697
Sam Zackrisson41478c72019-10-15 10:10:26 +02001698 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001699 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001700 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrisson0824c6f2019-10-07 14:03:56 +02001701 EXPECT_TRUE(stats.voice_detected);
1702 EXPECT_TRUE(stats.output_rms_dbfs);
1703 has_voice_count += *stats.voice_detected ? 1 : 0;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001704 rms_dbfs_average += *stats.output_rms_dbfs;
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001705
Per Åhgren2507f8c2020-03-19 12:33:29 +01001706 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001707 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001708 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001709 ASSERT_EQ(frame_size, write_count);
1710
1711 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001712 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001713 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001714
1715#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1716 const int kStatsAggregationFrameNum = 100; // 1 second.
1717 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001718 // Get echo and delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +01001719 AudioProcessingStats stats = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001720
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001721 // Echo metrics.
1722 const float echo_return_loss = stats.echo_return_loss.value_or(-1.0f);
1723 const float echo_return_loss_enhancement =
1724 stats.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001725 const float residual_echo_likelihood =
1726 stats.residual_echo_likelihood.value_or(-1.0f);
1727 const float residual_echo_likelihood_recent_max =
1728 stats.residual_echo_likelihood_recent_max.value_or(-1.0f);
1729
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001730 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001731 const audioproc::Test::EchoMetrics& reference =
1732 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001733 constexpr float kEpsilon = 0.01;
1734 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1735 EXPECT_NEAR(echo_return_loss_enhancement,
1736 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001737 EXPECT_NEAR(residual_echo_likelihood,
1738 reference.residual_echo_likelihood(), kEpsilon);
1739 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1740 reference.residual_echo_likelihood_recent_max(),
1741 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001742 ++stats_index;
1743 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001744 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1745 message_echo->set_echo_return_loss(echo_return_loss);
1746 message_echo->set_echo_return_loss_enhancement(
1747 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001748 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1749 message_echo->set_residual_echo_likelihood_recent_max(
1750 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001751 }
1752 }
1753#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001754 }
1755 max_output_average /= frame_count;
1756 analog_level_average /= frame_count;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001757 rms_dbfs_average /= frame_count;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001758
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001759 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001760 const int kIntNear = 1;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001761 // When running the test on a N7 we get a {2, 6} difference of
1762 // |has_voice_count| and |max_output_average| is up to 18 higher.
1763 // All numbers being consistently higher on N7 compare to ref_data.
1764 // TODO(bjornv): If we start getting more of these offsets on Android we
1765 // should consider a different approach. Either using one slack for all,
1766 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001767#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001768 const int kHasVoiceCountOffset = 3;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001769 const int kHasVoiceCountNear = 8;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001770 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001771 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001772#else
1773 const int kHasVoiceCountOffset = 0;
1774 const int kHasVoiceCountNear = kIntNear;
1775 const int kMaxOutputAverageOffset = 0;
1776 const int kMaxOutputAverageNear = kIntNear;
1777#endif
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001778 EXPECT_NEAR(test->has_voice_count(),
Jonas Olssona4d87372019-07-05 19:08:33 +02001779 has_voice_count - kHasVoiceCountOffset, kHasVoiceCountNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001780
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001781 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001782 EXPECT_NEAR(test->max_output_average(),
1783 max_output_average - kMaxOutputAverageOffset,
1784 kMaxOutputAverageNear);
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001785#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Per Åhgrena43178c2020-09-25 12:02:32 +02001786 const double kFloatNear = 0.002;
Sam Zackrisson11b87032018-12-18 17:13:58 +01001787 EXPECT_NEAR(test->rms_dbfs_average(), rms_dbfs_average, kFloatNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001788#endif
1789 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001790 test->set_has_voice_count(has_voice_count);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001791
1792 test->set_analog_level_average(analog_level_average);
1793 test->set_max_output_average(max_output_average);
1794
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00001795#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrisson11b87032018-12-18 17:13:58 +01001796 test->set_rms_dbfs_average(rms_dbfs_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001797#endif
1798 }
1799
1800 rewind(far_file_);
1801 rewind(near_file_);
1802 }
1803
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001804 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001805 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001806 }
1807}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001808
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001809TEST_F(ApmTest, NoErrorsWithKeyboardChannel) {
1810 struct ChannelFormat {
1811 AudioProcessing::ChannelLayout in_layout;
1812 AudioProcessing::ChannelLayout out_layout;
1813 };
1814 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02001815 {AudioProcessing::kMonoAndKeyboard, AudioProcessing::kMono},
1816 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kMono},
1817 {AudioProcessing::kStereoAndKeyboard, AudioProcessing::kStereo},
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001818 };
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001819
Per Åhgrencc73ed32020-04-26 23:56:17 +02001820 std::unique_ptr<AudioProcessing> ap(
1821 AudioProcessingBuilderForTesting().Create());
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001822 // Enable one component just to ensure some processing takes place.
saza0bad15f2019-10-16 11:46:11 +02001823 AudioProcessing::Config config;
1824 config.noise_suppression.enabled = true;
1825 ap->ApplyConfig(config);
pkasting25702cb2016-01-08 13:50:27 -08001826 for (size_t i = 0; i < arraysize(cf); ++i) {
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001827 const int in_rate = 44100;
1828 const int out_rate = 48000;
1829 ChannelBuffer<float> in_cb(SamplesFromRate(in_rate),
1830 TotalChannelsFromLayout(cf[i].in_layout));
1831 ChannelBuffer<float> out_cb(SamplesFromRate(out_rate),
1832 ChannelsFromLayout(cf[i].out_layout));
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001833 bool has_keyboard = cf[i].in_layout == AudioProcessing::kMonoAndKeyboard ||
1834 cf[i].in_layout == AudioProcessing::kStereoAndKeyboard;
1835 StreamConfig in_sc(in_rate, ChannelsFromLayout(cf[i].in_layout),
1836 has_keyboard);
1837 StreamConfig out_sc(out_rate, ChannelsFromLayout(cf[i].out_layout));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001838
1839 // Run over a few chunks.
1840 for (int j = 0; j < 10; ++j) {
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001841 EXPECT_NOERR(ap->ProcessStream(in_cb.channels(), in_sc, out_sc,
1842 out_cb.channels()));
andrew@webrtc.org103657b2014-04-24 18:28:56 +00001843 }
1844 }
1845}
1846
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001847// Compares the reference and test arrays over a region around the expected
1848// delay. Finds the highest SNR in that region and adds the variance and squared
1849// error results to the supplied accumulators.
1850void UpdateBestSNR(const float* ref,
1851 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001852 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001853 int expected_delay,
1854 double* variance_acc,
1855 double* sq_error_acc) {
1856 double best_snr = std::numeric_limits<double>::min();
1857 double best_variance = 0;
1858 double best_sq_error = 0;
1859 // Search over a region of eight samples around the expected delay.
1860 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1861 ++delay) {
1862 double sq_error = 0;
1863 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001864 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001865 double error = test[i + delay] - ref[i];
1866 sq_error += error * error;
1867 variance += ref[i] * ref[i];
1868 }
1869
1870 if (sq_error == 0) {
1871 *variance_acc += variance;
1872 return;
1873 }
1874 double snr = variance / sq_error;
1875 if (snr > best_snr) {
1876 best_snr = snr;
1877 best_variance = variance;
1878 best_sq_error = sq_error;
1879 }
1880 }
1881
1882 *variance_acc += best_variance;
1883 *sq_error_acc += best_sq_error;
1884}
1885
1886// Used to test a multitude of sample rate and channel combinations. It works
1887// by first producing a set of reference files (in SetUpTestCase) that are
1888// assumed to be correct, as the used parameters are verified by other tests
1889// in this collection. Primarily the reference files are all produced at
1890// "native" rates which do not involve any resampling.
1891
1892// Each test pass produces an output file with a particular format. The output
1893// is matched against the reference file closest to its internal processing
1894// format. If necessary the output is resampled back to its process format.
1895// Due to the resampling distortion, we don't expect identical results, but
1896// enforce SNR thresholds which vary depending on the format. 0 is a special
1897// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001898typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001899class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001900 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001901 public:
1902 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001903 : input_rate_(std::get<0>(GetParam())),
1904 output_rate_(std::get<1>(GetParam())),
1905 reverse_input_rate_(std::get<2>(GetParam())),
1906 reverse_output_rate_(std::get<3>(GetParam())),
1907 expected_snr_(std::get<4>(GetParam())),
1908 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001909
1910 virtual ~AudioProcessingTest() {}
1911
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001912 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001913 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07001914 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08001915 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08001916 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
1917 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1918 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001919 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07001920 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
1921 kNativeRates[i], kNumChannels[j], kNumChannels[j],
1922 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001923 }
1924 }
1925 }
1926 }
1927
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001928 void TearDown() {
1929 // Remove "out" files after each test.
1930 ClearTempOutFiles();
1931 }
1932
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001933 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001934
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001935 // Runs a process pass on files with the given parameters and dumps the output
ekmeyerson60d9b332015-08-14 10:35:55 -07001936 // to a file specified with |output_file_prefix|. Both forward and reverse
1937 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001938 static void ProcessFormat(int input_rate,
1939 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001940 int reverse_input_rate,
1941 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001942 size_t num_input_channels,
1943 size_t num_output_channels,
1944 size_t num_reverse_input_channels,
1945 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02001946 const std::string& output_file_prefix) {
Per Åhgrencc73ed32020-04-26 23:56:17 +02001947 std::unique_ptr<AudioProcessing> ap(
1948 AudioProcessingBuilderForTesting().Create());
Per Åhgren0695df12020-01-13 14:43:13 +01001949 AudioProcessing::Config apm_config = ap->GetConfig();
1950 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1951 ap->ApplyConfig(apm_config);
1952
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001953 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001954
ekmeyerson60d9b332015-08-14 10:35:55 -07001955 ProcessingConfig processing_config = {
1956 {{input_rate, num_input_channels},
1957 {output_rate, num_output_channels},
1958 {reverse_input_rate, num_reverse_input_channels},
1959 {reverse_output_rate, num_reverse_output_channels}}};
1960 ap->Initialize(processing_config);
1961
1962 FILE* far_file =
1963 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001964 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02001965 FILE* out_file = fopen(
1966 OutputFilePath(
1967 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1968 reverse_output_rate, num_input_channels, num_output_channels,
1969 num_reverse_input_channels, num_reverse_output_channels, kForward)
1970 .c_str(),
1971 "wb");
1972 FILE* rev_out_file = fopen(
1973 OutputFilePath(
1974 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1975 reverse_output_rate, num_input_channels, num_output_channels,
1976 num_reverse_input_channels, num_reverse_output_channels, kReverse)
1977 .c_str(),
1978 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001979 ASSERT_TRUE(far_file != NULL);
1980 ASSERT_TRUE(near_file != NULL);
1981 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07001982 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001983
1984 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
1985 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07001986 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
1987 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001988 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
1989 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07001990 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
1991 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001992
1993 // Temporary buffers.
1994 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07001995 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
1996 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08001997 std::unique_ptr<float[]> float_data(new float[max_length]);
1998 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001999
2000 int analog_level = 127;
2001 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2002 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002003 EXPECT_NOERR(ap->ProcessReverseStream(
2004 rev_cb.channels(), processing_config.reverse_input_stream(),
2005 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002006
2007 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02002008 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002009
2010 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01002011 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2012 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002013
ekmeyerson60d9b332015-08-14 10:35:55 -07002014 // Dump forward output to file.
2015 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002016 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002017 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002018
Jonas Olssona4d87372019-07-05 19:08:33 +02002019 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2020 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002021
ekmeyerson60d9b332015-08-14 10:35:55 -07002022 // Dump reverse output to file.
2023 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2024 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08002025 size_t rev_out_length =
2026 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07002027
Jonas Olssona4d87372019-07-05 19:08:33 +02002028 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2029 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07002030
Sam Zackrisson41478c72019-10-15 10:10:26 +02002031 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002032 }
2033 fclose(far_file);
2034 fclose(near_file);
2035 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002036 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002037 }
2038
2039 protected:
2040 int input_rate_;
2041 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002042 int reverse_input_rate_;
2043 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002044 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002045 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002046};
2047
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002048TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002049 struct ChannelFormat {
2050 int num_input;
2051 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002052 int num_reverse_input;
2053 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002054 };
2055 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002056 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2057 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002058 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002059
pkasting25702cb2016-01-08 13:50:27 -08002060 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002061 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2062 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2063 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002064
ekmeyerson60d9b332015-08-14 10:35:55 -07002065 // Verify output for both directions.
2066 std::vector<StreamDirection> stream_directions;
2067 stream_directions.push_back(kForward);
2068 stream_directions.push_back(kReverse);
2069 for (StreamDirection file_direction : stream_directions) {
2070 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2071 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2072 const int out_num =
2073 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2074 const double expected_snr =
2075 file_direction ? expected_reverse_snr_ : expected_snr_;
2076
2077 const int min_ref_rate = std::min(in_rate, out_rate);
2078 int ref_rate;
2079
2080 if (min_ref_rate > 32000) {
2081 ref_rate = 48000;
2082 } else if (min_ref_rate > 16000) {
2083 ref_rate = 32000;
2084 } else if (min_ref_rate > 8000) {
2085 ref_rate = 16000;
2086 } else {
2087 ref_rate = 8000;
2088 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002089
ekmeyerson60d9b332015-08-14 10:35:55 -07002090 FILE* out_file = fopen(
2091 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2092 reverse_output_rate_, cf[i].num_input,
2093 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002094 cf[i].num_reverse_output, file_direction)
2095 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002096 "rb");
2097 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002098 FILE* ref_file =
2099 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2100 cf[i].num_output, cf[i].num_output,
2101 cf[i].num_reverse_output,
2102 cf[i].num_reverse_output, file_direction)
2103 .c_str(),
2104 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002105 ASSERT_TRUE(out_file != NULL);
2106 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002107
pkasting25702cb2016-01-08 13:50:27 -08002108 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2109 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002110 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002111 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002112 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002113 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002114 // Data from the resampled output, in case the reference and output rates
2115 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002116 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002117
ekmeyerson60d9b332015-08-14 10:35:55 -07002118 PushResampler<float> resampler;
2119 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002120
ekmeyerson60d9b332015-08-14 10:35:55 -07002121 // Compute the resampling delay of the output relative to the reference,
2122 // to find the region over which we should search for the best SNR.
2123 float expected_delay_sec = 0;
2124 if (in_rate != ref_rate) {
2125 // Input resampling delay.
2126 expected_delay_sec +=
2127 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2128 }
2129 if (out_rate != ref_rate) {
2130 // Output resampling delay.
2131 expected_delay_sec +=
2132 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2133 // Delay of converting the output back to its processing rate for
2134 // testing.
2135 expected_delay_sec +=
2136 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2137 }
2138 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002139 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002140
ekmeyerson60d9b332015-08-14 10:35:55 -07002141 double variance = 0;
2142 double sq_error = 0;
2143 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2144 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2145 float* out_ptr = out_data.get();
2146 if (out_rate != ref_rate) {
2147 // Resample the output back to its internal processing rate if
2148 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002149 ASSERT_EQ(ref_length,
2150 static_cast<size_t>(resampler.Resample(
2151 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002152 out_ptr = cmp_data.get();
2153 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002154
ekmeyerson60d9b332015-08-14 10:35:55 -07002155 // Update the |sq_error| and |variance| accumulators with the highest
2156 // SNR of reference vs output.
2157 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2158 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002159 }
2160
ekmeyerson60d9b332015-08-14 10:35:55 -07002161 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2162 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2163 << cf[i].num_input << ", " << cf[i].num_output << ", "
2164 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2165 << ", " << file_direction << "): ";
2166 if (sq_error > 0) {
2167 double snr = 10 * log10(variance / sq_error);
2168 EXPECT_GE(snr, expected_snr);
2169 EXPECT_NE(0, expected_snr);
2170 std::cout << "SNR=" << snr << " dB" << std::endl;
2171 } else {
aluebs776593b2016-03-15 14:04:58 -07002172 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002173 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002174
ekmeyerson60d9b332015-08-14 10:35:55 -07002175 fclose(out_file);
2176 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002177 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002178 }
2179}
2180
2181#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002182INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002183 CommonFormats,
2184 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002185 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2186 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2187 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2188 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2189 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2190 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2191 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2192 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2193 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2194 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2195 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2196 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002197
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002198 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2199 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2200 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2201 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2202 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2203 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2204 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2205 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2206 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2207 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2208 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2209 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002210
Per Åhgrenc0424252019-12-10 13:04:15 +01002211 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2212 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2213 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002214 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2215 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2216 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2217 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2218 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002219 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002220 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2221 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2222 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002223
Per Åhgrenc0424252019-12-10 13:04:15 +01002224 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2225 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2226 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002227 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2228 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2229 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2230 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2231 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2232 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2233 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002234 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002235 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002236
2237#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002238INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002239 CommonFormats,
2240 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002241 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2242 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2243 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002244 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2245 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2246 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002247 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2248 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2249 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002250 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2251 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2252 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002253
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002254 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2255 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2256 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2257 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2258 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2259 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002260 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2261 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2262 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2263 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2264 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2265 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002266
Per Åhgrenc0424252019-12-10 13:04:15 +01002267 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2268 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2269 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002270 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2271 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2272 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002273 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002274 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002275 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002276 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2277 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2278 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002279
Per Åhgrenc0424252019-12-10 13:04:15 +01002280 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2281 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2282 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002283 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2284 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2285 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002286 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002287 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002288 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002289 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2290 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002291 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002292#endif
2293
Per Åhgren3e8bf282019-08-29 23:38:40 +02002294// Produces a scoped trace debug output.
2295std::string ProduceDebugText(int render_input_sample_rate_hz,
2296 int render_output_sample_rate_hz,
2297 int capture_input_sample_rate_hz,
2298 int capture_output_sample_rate_hz,
2299 size_t render_input_num_channels,
2300 size_t render_output_num_channels,
2301 size_t capture_input_num_channels,
2302 size_t capture_output_num_channels) {
2303 rtc::StringBuilder ss;
2304 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002305 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002306 << render_input_sample_rate_hz
2307 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002308 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002309 << render_output_sample_rate_hz
2310 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002311 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002312 << capture_input_sample_rate_hz
2313 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002314 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002315 << capture_output_sample_rate_hz
2316 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002317 "\nNumber of channels:"
2318 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002319 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002320 << "\n Render output: " << render_output_num_channels
2321 << "\n Capture input: " << capture_input_num_channels
2322 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002323 return ss.Release();
2324}
2325
2326// Validates that running the audio processing module using various combinations
2327// of sample rates and number of channels works as intended.
2328void RunApmRateAndChannelTest(
2329 rtc::ArrayView<const int> sample_rates_hz,
2330 rtc::ArrayView<const int> render_channel_counts,
2331 rtc::ArrayView<const int> capture_channel_counts) {
Per Åhgrencc73ed32020-04-26 23:56:17 +02002332 std::unique_ptr<AudioProcessing> apm(
2333 AudioProcessingBuilderForTesting().Create());
Per Åhgren3e8bf282019-08-29 23:38:40 +02002334 webrtc::AudioProcessing::Config apm_config;
2335 apm_config.echo_canceller.enabled = true;
2336 apm->ApplyConfig(apm_config);
2337
2338 StreamConfig render_input_stream_config;
2339 StreamConfig render_output_stream_config;
2340 StreamConfig capture_input_stream_config;
2341 StreamConfig capture_output_stream_config;
2342
2343 std::vector<float> render_input_frame_channels;
2344 std::vector<float*> render_input_frame;
2345 std::vector<float> render_output_frame_channels;
2346 std::vector<float*> render_output_frame;
2347 std::vector<float> capture_input_frame_channels;
2348 std::vector<float*> capture_input_frame;
2349 std::vector<float> capture_output_frame_channels;
2350 std::vector<float*> capture_output_frame;
2351
2352 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2353 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2354 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2355 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2356 for (size_t render_input_num_channels : render_channel_counts) {
2357 for (size_t capture_input_num_channels : capture_channel_counts) {
2358 size_t render_output_num_channels = render_input_num_channels;
2359 size_t capture_output_num_channels = capture_input_num_channels;
2360 auto populate_audio_frame = [](int sample_rate_hz,
2361 size_t num_channels,
2362 StreamConfig* cfg,
2363 std::vector<float>* channels_data,
2364 std::vector<float*>* frame_data) {
2365 cfg->set_sample_rate_hz(sample_rate_hz);
2366 cfg->set_num_channels(num_channels);
2367 cfg->set_has_keyboard(false);
2368
2369 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2370 channels_data->resize(num_channels * max_frame_size);
2371 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2372 frame_data->resize(num_channels);
2373 for (size_t channel = 0; channel < num_channels; ++channel) {
2374 (*frame_data)[channel] =
2375 &(*channels_data)[channel * max_frame_size];
2376 }
2377 };
2378
2379 populate_audio_frame(
2380 render_input_sample_rate_hz, render_input_num_channels,
2381 &render_input_stream_config, &render_input_frame_channels,
2382 &render_input_frame);
2383 populate_audio_frame(
2384 render_output_sample_rate_hz, render_output_num_channels,
2385 &render_output_stream_config, &render_output_frame_channels,
2386 &render_output_frame);
2387 populate_audio_frame(
2388 capture_input_sample_rate_hz, capture_input_num_channels,
2389 &capture_input_stream_config, &capture_input_frame_channels,
2390 &capture_input_frame);
2391 populate_audio_frame(
2392 capture_output_sample_rate_hz, capture_output_num_channels,
2393 &capture_output_stream_config, &capture_output_frame_channels,
2394 &capture_output_frame);
2395
2396 for (size_t frame = 0; frame < 2; ++frame) {
2397 SCOPED_TRACE(ProduceDebugText(
2398 render_input_sample_rate_hz, render_output_sample_rate_hz,
2399 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2400 render_input_num_channels, render_output_num_channels,
2401 render_input_num_channels, capture_output_num_channels));
2402
2403 int result = apm->ProcessReverseStream(
2404 &render_input_frame[0], render_input_stream_config,
2405 render_output_stream_config, &render_output_frame[0]);
2406 EXPECT_EQ(result, AudioProcessing::kNoError);
2407 result = apm->ProcessStream(
2408 &capture_input_frame[0], capture_input_stream_config,
2409 capture_output_stream_config, &capture_output_frame[0]);
2410 EXPECT_EQ(result, AudioProcessing::kNoError);
2411 }
2412 }
2413 }
2414 }
2415 }
2416 }
2417 }
2418}
2419
Alessio Bazzica3438a932020-10-14 12:47:50 +02002420constexpr void Toggle(bool& b) {
2421 b ^= true;
2422}
2423
niklase@google.com470e71d2011-07-07 08:21:25 +00002424} // namespace
peahc19f3122016-10-07 14:54:10 -07002425
Alessio Bazzicac054e782018-04-16 12:10:09 +02002426TEST(RuntimeSettingTest, TestDefaultCtor) {
2427 auto s = AudioProcessing::RuntimeSetting();
2428 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2429}
2430
Tommia5e07cc2020-05-26 21:40:37 +02002431TEST(RuntimeSettingDeathTest, TestCapturePreGain) {
Alessio Bazzicac054e782018-04-16 12:10:09 +02002432 using Type = AudioProcessing::RuntimeSetting::Type;
2433 {
2434 auto s = AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.25f);
2435 EXPECT_EQ(Type::kCapturePreGain, s.type());
2436 float v;
2437 s.GetFloat(&v);
2438 EXPECT_EQ(1.25f, v);
2439 }
2440
2441#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
2442 EXPECT_DEATH(AudioProcessing::RuntimeSetting::CreateCapturePreGain(0.1f), "");
2443#endif
2444}
2445
Tommia5e07cc2020-05-26 21:40:37 +02002446TEST(RuntimeSettingDeathTest, TestCaptureFixedPostGain) {
Per Åhgren6ee75fd2019-04-26 11:33:37 +02002447 using Type = AudioProcessing::RuntimeSetting::Type;
2448 {
2449 auto s = AudioProcessing::RuntimeSetting::CreateCaptureFixedPostGain(1.25f);
2450 EXPECT_EQ(Type::kCaptureFixedPostGain, s.type());
2451 float v;
2452 s.GetFloat(&v);
2453 EXPECT_EQ(1.25f, v);
2454 }
2455
2456#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
2457 EXPECT_DEATH(AudioProcessing::RuntimeSetting::CreateCapturePreGain(0.1f), "");
2458#endif
2459}
2460
Alessio Bazzicac054e782018-04-16 12:10:09 +02002461TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2462 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2463 auto s = AudioProcessing::RuntimeSetting();
2464 ASSERT_TRUE(q.Insert(&s));
2465 ASSERT_TRUE(q.Remove(&s));
2466 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2467}
2468
Sam Zackrisson0beac582017-09-25 12:04:02 +02002469TEST(ApmConfiguration, EnablePostProcessing) {
2470 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002471 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002472 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002473 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002474 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002475 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002476 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002477 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002478 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002479
Per Åhgren2507f8c2020-03-19 12:33:29 +01002480 Int16FrameData audio;
2481 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002482 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2483
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002484 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002485 apm->ProcessStream(audio.data.data(),
2486 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2487 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002488 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002489}
2490
Alex Loiko5825aa62017-12-18 16:02:40 +01002491TEST(ApmConfiguration, EnablePreProcessing) {
2492 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002493 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002494 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002495 auto mock_pre_processor =
2496 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002497 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002498 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002499 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002500 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002501
Per Åhgren2507f8c2020-03-19 12:33:29 +01002502 Int16FrameData audio;
2503 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002504 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2505
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002506 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002507 apm->ProcessReverseStream(
2508 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2509 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2510 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002511}
2512
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002513TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2514 // Verify that apm uses a capture analyzer if one is provided.
2515 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002516 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002517 auto mock_capture_analyzer =
2518 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2519 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002520 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002521 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2522 .Create();
2523
Per Åhgren2507f8c2020-03-19 12:33:29 +01002524 Int16FrameData audio;
2525 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002526 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2527
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002528 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002529 apm->ProcessStream(audio.data.data(),
2530 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2531 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002532 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002533}
2534
Alex Loiko73ec0192018-05-15 10:52:28 +02002535TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2536 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002537 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002538 auto mock_pre_processor =
2539 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2540 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002541 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002542 .SetRenderPreProcessing(std::move(mock_pre_processor))
2543 .Create();
2544 apm->SetRuntimeSetting(
2545 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2546
2547 // RuntimeSettings forwarded during 'Process*Stream' calls.
2548 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002549 Int16FrameData audio;
2550 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002551 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2552
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002553 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2554 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002555 apm->ProcessReverseStream(
2556 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2557 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2558 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002559}
2560
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002561class MyEchoControlFactory : public EchoControlFactory {
2562 public:
2563 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2564 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002565 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2566 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002567 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2568 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002569 return std::unique_ptr<EchoControl>(ec);
2570 }
Per Åhgrence202a02019-09-02 17:01:19 +02002571
2572 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002573 int num_render_channels,
2574 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002575 return Create(sample_rate_hz);
2576 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002577};
2578
2579TEST(ApmConfiguration, EchoControlInjection) {
2580 // Verify that apm uses an injected echo controller if one is provided.
2581 webrtc::Config webrtc_config;
2582 std::unique_ptr<EchoControlFactory> echo_control_factory(
2583 new MyEchoControlFactory());
2584
Alex Loiko5825aa62017-12-18 16:02:40 +01002585 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002586 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002587 .SetEchoControlFactory(std::move(echo_control_factory))
2588 .Create(webrtc_config);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002589
Per Åhgren2507f8c2020-03-19 12:33:29 +01002590 Int16FrameData audio;
2591 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002592 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002593 apm->ProcessStream(audio.data.data(),
2594 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2595 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002596 audio.data.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002597 apm->ProcessReverseStream(
2598 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2599 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2600 audio.data.data());
2601 apm->ProcessStream(audio.data.data(),
2602 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2603 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002604 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002605}
Ivo Creusenae026092017-11-20 13:07:16 +01002606
Per Åhgren8607f842019-04-12 22:02:26 +02002607std::unique_ptr<AudioProcessing> CreateApm(bool mobile_aec) {
Ivo Creusenae026092017-11-20 13:07:16 +01002608 Config old_config;
Ivo Creusen62337e52018-01-09 14:17:33 +01002609 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +02002610 AudioProcessingBuilderForTesting().Create(old_config));
Ivo Creusenae026092017-11-20 13:07:16 +01002611 if (!apm) {
2612 return apm;
2613 }
2614
2615 ProcessingConfig processing_config = {
2616 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2617
2618 if (apm->Initialize(processing_config) != 0) {
2619 return nullptr;
2620 }
2621
2622 // Disable all components except for an AEC and the residual echo detector.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002623 AudioProcessing::Config apm_config;
2624 apm_config.residual_echo_detector.enabled = true;
2625 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 10:10:26 +02002626 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002627 apm_config.gain_controller2.enabled = false;
2628 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 22:02:26 +02002629 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 11:46:11 +02002630 apm_config.noise_suppression.enabled = false;
2631 apm_config.level_estimation.enabled = false;
2632 apm_config.voice_detection.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002633 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002634 return apm;
2635}
2636
2637#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2638#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2639#else
2640#define MAYBE_ApmStatistics ApmStatistics
2641#endif
2642
Per Åhgren8607f842019-04-12 22:02:26 +02002643TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2644 // Set up APM with AEC3 and process some audio.
2645 std::unique_ptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002646 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002647 AudioProcessing::Config apm_config;
2648 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002649 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002650
2651 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002652 Int16FrameData frame;
2653 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002654 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002655
2656 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002657 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002658 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2659 ptr[i] = 10000 * ((i % 3) - 1);
2660 }
2661
2662 // Do some processing.
2663 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002664 EXPECT_EQ(apm->ProcessReverseStream(
2665 frame.data.data(),
2666 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2667 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2668 frame.data.data()),
2669 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002670 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002671 EXPECT_EQ(apm->ProcessStream(
2672 frame.data.data(),
2673 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2674 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002675 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002676 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002677 }
2678
2679 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002680 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002681 // We expect all statistics to be set and have a sensible value.
2682 ASSERT_TRUE(stats.residual_echo_likelihood);
2683 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2684 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2685 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max);
2686 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2687 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2688 ASSERT_TRUE(stats.echo_return_loss);
2689 EXPECT_NE(*stats.echo_return_loss, -100.0);
2690 ASSERT_TRUE(stats.echo_return_loss_enhancement);
2691 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002692}
2693
2694TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2695 // Set up APM with AECM and process some audio.
Per Åhgren8607f842019-04-12 22:02:26 +02002696 std::unique_ptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002697 ASSERT_TRUE(apm);
2698
2699 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002700 Int16FrameData frame;
2701 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002702 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002703
2704 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002705 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002706 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2707 ptr[i] = 10000 * ((i % 3) - 1);
2708 }
2709
2710 // Do some processing.
2711 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002712 EXPECT_EQ(apm->ProcessReverseStream(
2713 frame.data.data(),
2714 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2715 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2716 frame.data.data()),
2717 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002718 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002719 EXPECT_EQ(apm->ProcessStream(
2720 frame.data.data(),
2721 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2722 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002723 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002724 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002725 }
2726
2727 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002728 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002729 // We expect only the residual echo detector statistics to be set and have a
2730 // sensible value.
2731 EXPECT_TRUE(stats.residual_echo_likelihood);
2732 if (stats.residual_echo_likelihood) {
2733 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2734 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2735 }
2736 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max);
2737 if (stats.residual_echo_likelihood_recent_max) {
2738 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2739 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2740 }
2741 EXPECT_FALSE(stats.echo_return_loss);
2742 EXPECT_FALSE(stats.echo_return_loss_enhancement);
Ivo Creusenae026092017-11-20 13:07:16 +01002743}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002744
2745TEST(ApmStatistics, ReportOutputRmsDbfs) {
2746 ProcessingConfig processing_config = {
2747 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2748 AudioProcessing::Config config;
2749
2750 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002751 Int16FrameData frame;
2752 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002753 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002754
2755 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002756 int16_t* ptr = frame.data.data();
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002757 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2758 ptr[i] = 10000 * ((i % 3) - 1);
2759 }
2760
Per Åhgrencc73ed32020-04-26 23:56:17 +02002761 std::unique_ptr<AudioProcessing> apm(
2762 AudioProcessingBuilderForTesting().Create());
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002763 apm->Initialize(processing_config);
2764
2765 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002766 EXPECT_EQ(
2767 apm->ProcessStream(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);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002772 EXPECT_FALSE(apm->GetStatistics().output_rms_dbfs);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002773
2774 // If enabled, metrics should be reported.
2775 config.level_estimation.enabled = true;
2776 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002777 EXPECT_EQ(
2778 apm->ProcessStream(frame.data.data(),
2779 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2780 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002781 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002782 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002783 auto stats = apm->GetStatistics();
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002784 EXPECT_TRUE(stats.output_rms_dbfs);
2785 EXPECT_GE(*stats.output_rms_dbfs, 0);
2786
2787 // If re-disabled, the value is again not reported.
2788 config.level_estimation.enabled = false;
2789 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002790 EXPECT_EQ(
2791 apm->ProcessStream(frame.data.data(),
2792 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2793 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002794 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002795 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002796 EXPECT_FALSE(apm->GetStatistics().output_rms_dbfs);
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002797}
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002798
2799TEST(ApmStatistics, ReportHasVoice) {
2800 ProcessingConfig processing_config = {
2801 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2802 AudioProcessing::Config config;
2803
2804 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002805 Int16FrameData frame;
2806 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002807 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2808
2809 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002810 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002811 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2812 ptr[i] = 10000 * ((i % 3) - 1);
2813 }
2814
Per Åhgrencc73ed32020-04-26 23:56:17 +02002815 std::unique_ptr<AudioProcessing> apm(
2816 AudioProcessingBuilderForTesting().Create());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002817 apm->Initialize(processing_config);
2818
2819 // If not enabled, no metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002820 EXPECT_EQ(
2821 apm->ProcessStream(frame.data.data(),
2822 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2823 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002824 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002825 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002826 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002827
2828 // If enabled, metrics should be reported.
2829 config.voice_detection.enabled = true;
2830 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002831 EXPECT_EQ(
2832 apm->ProcessStream(frame.data.data(),
2833 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2834 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002835 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002836 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002837 auto stats = apm->GetStatistics();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002838 EXPECT_TRUE(stats.voice_detected);
2839
2840 // If re-disabled, the value is again not reported.
2841 config.voice_detection.enabled = false;
2842 apm->ApplyConfig(config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002843 EXPECT_EQ(
2844 apm->ProcessStream(frame.data.data(),
2845 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2846 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002847 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002848 0);
Per Åhgrencf4c8722019-12-30 14:32:14 +01002849 EXPECT_FALSE(apm->GetStatistics().voice_detected);
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002850}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002851
2852TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2853 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2854 std::array<int, 2> render_channel_counts = {1, 7};
2855 std::array<int, 2> capture_channel_counts = {1, 7};
2856 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2857 capture_channel_counts);
2858}
2859
2860TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2861 std::array<int, 1> sample_rates_hz = {48000};
2862 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2863 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2864 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2865 capture_channel_counts);
2866}
2867
2868TEST(ApmConfiguration, HandlingOfRateCombinations) {
2869 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2870 48000, 96000, 192000, 384000};
2871 std::array<int, 1> render_channel_counts = {2};
2872 std::array<int, 1> capture_channel_counts = {2};
2873 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2874 capture_channel_counts);
2875}
2876
Yves Gerey1fce3f82019-12-05 17:45:31 +01002877TEST(ApmConfiguration, SelfAssignment) {
2878 // At some point memory sanitizer was complaining about self-assigment.
2879 // Make sure we don't regress.
2880 AudioProcessing::Config config;
2881 AudioProcessing::Config* config2 = &config;
2882 *config2 = *config2; // Workaround -Wself-assign-overloaded
2883 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2884}
2885
Alessio Bazzica3438a932020-10-14 12:47:50 +02002886TEST(AudioProcessing, GainController1ConfigEqual) {
2887 AudioProcessing::Config::GainController1 a;
2888 AudioProcessing::Config::GainController1 b;
2889 EXPECT_EQ(a, b);
2890
2891 Toggle(a.enabled);
2892 b.enabled = a.enabled;
2893 EXPECT_EQ(a, b);
2894
2895 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2896 b.mode = a.mode;
2897 EXPECT_EQ(a, b);
2898
2899 a.target_level_dbfs++;
2900 b.target_level_dbfs = a.target_level_dbfs;
2901 EXPECT_EQ(a, b);
2902
2903 a.compression_gain_db++;
2904 b.compression_gain_db = a.compression_gain_db;
2905 EXPECT_EQ(a, b);
2906
2907 Toggle(a.enable_limiter);
2908 b.enable_limiter = a.enable_limiter;
2909 EXPECT_EQ(a, b);
2910
2911 a.analog_level_minimum++;
2912 b.analog_level_minimum = a.analog_level_minimum;
2913 EXPECT_EQ(a, b);
2914
2915 a.analog_level_maximum--;
2916 b.analog_level_maximum = a.analog_level_maximum;
2917 EXPECT_EQ(a, b);
2918
2919 auto& a_analog = a.analog_gain_controller;
2920 auto& b_analog = b.analog_gain_controller;
2921
2922 Toggle(a_analog.enabled);
2923 b_analog.enabled = a_analog.enabled;
2924 EXPECT_EQ(a, b);
2925
2926 a_analog.startup_min_volume++;
2927 b_analog.startup_min_volume = a_analog.startup_min_volume;
2928 EXPECT_EQ(a, b);
2929
2930 a_analog.clipped_level_min++;
2931 b_analog.clipped_level_min = a_analog.clipped_level_min;
2932 EXPECT_EQ(a, b);
2933
Alessio Bazzica3438a932020-10-14 12:47:50 +02002934 Toggle(a_analog.enable_digital_adaptive);
2935 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2936 EXPECT_EQ(a, b);
2937}
2938
2939// Checks that one differing parameter is sufficient to make two configs
2940// different.
2941TEST(AudioProcessing, GainController1ConfigNotEqual) {
2942 AudioProcessing::Config::GainController1 a;
2943 const AudioProcessing::Config::GainController1 b;
2944
2945 Toggle(a.enabled);
2946 EXPECT_NE(a, b);
2947 a.enabled = b.enabled;
2948
2949 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2950 EXPECT_NE(a, b);
2951 a.mode = b.mode;
2952
2953 a.target_level_dbfs++;
2954 EXPECT_NE(a, b);
2955 a.target_level_dbfs = b.target_level_dbfs;
2956
2957 a.compression_gain_db++;
2958 EXPECT_NE(a, b);
2959 a.compression_gain_db = b.compression_gain_db;
2960
2961 Toggle(a.enable_limiter);
2962 EXPECT_NE(a, b);
2963 a.enable_limiter = b.enable_limiter;
2964
2965 a.analog_level_minimum++;
2966 EXPECT_NE(a, b);
2967 a.analog_level_minimum = b.analog_level_minimum;
2968
2969 a.analog_level_maximum--;
2970 EXPECT_NE(a, b);
2971 a.analog_level_maximum = b.analog_level_maximum;
2972
2973 auto& a_analog = a.analog_gain_controller;
2974 const auto& b_analog = b.analog_gain_controller;
2975
2976 Toggle(a_analog.enabled);
2977 EXPECT_NE(a, b);
2978 a_analog.enabled = b_analog.enabled;
2979
2980 a_analog.startup_min_volume++;
2981 EXPECT_NE(a, b);
2982 a_analog.startup_min_volume = b_analog.startup_min_volume;
2983
2984 a_analog.clipped_level_min++;
2985 EXPECT_NE(a, b);
2986 a_analog.clipped_level_min = b_analog.clipped_level_min;
2987
Alessio Bazzica3438a932020-10-14 12:47:50 +02002988 Toggle(a_analog.enable_digital_adaptive);
2989 EXPECT_NE(a, b);
2990 a_analog.enable_digital_adaptive = b_analog.enable_digital_adaptive;
2991}
2992
2993TEST(AudioProcessing, GainController2ConfigEqual) {
2994 AudioProcessing::Config::GainController2 a;
2995 AudioProcessing::Config::GainController2 b;
2996 EXPECT_EQ(a, b);
2997
2998 Toggle(a.enabled);
2999 b.enabled = a.enabled;
3000 EXPECT_EQ(a, b);
3001
3002 a.fixed_digital.gain_db += 1.f;
3003 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3004 EXPECT_EQ(a, b);
3005
3006 auto& a_adaptive = a.adaptive_digital;
3007 auto& b_adaptive = b.adaptive_digital;
3008
3009 Toggle(a_adaptive.enabled);
3010 b_adaptive.enabled = a_adaptive.enabled;
3011 EXPECT_EQ(a, b);
3012
3013 a_adaptive.vad_probability_attack += 1.f;
3014 b_adaptive.vad_probability_attack = a_adaptive.vad_probability_attack;
3015 EXPECT_EQ(a, b);
3016
3017 a_adaptive.level_estimator =
3018 AudioProcessing::Config::GainController2::LevelEstimator::kPeak;
3019 b_adaptive.level_estimator = a_adaptive.level_estimator;
3020 EXPECT_EQ(a, b);
3021
3022 a_adaptive.level_estimator_adjacent_speech_frames_threshold++;
3023 b_adaptive.level_estimator_adjacent_speech_frames_threshold =
3024 a_adaptive.level_estimator_adjacent_speech_frames_threshold;
3025 EXPECT_EQ(a, b);
3026
3027 Toggle(a_adaptive.use_saturation_protector);
3028 b_adaptive.use_saturation_protector = a_adaptive.use_saturation_protector;
3029 EXPECT_EQ(a, b);
3030
3031 a_adaptive.initial_saturation_margin_db += 1.f;
3032 b_adaptive.initial_saturation_margin_db =
3033 a_adaptive.initial_saturation_margin_db;
3034 EXPECT_EQ(a, b);
3035
3036 a_adaptive.extra_saturation_margin_db += 1.f;
3037 b_adaptive.extra_saturation_margin_db = a_adaptive.extra_saturation_margin_db;
3038 EXPECT_EQ(a, b);
3039
3040 a_adaptive.gain_applier_adjacent_speech_frames_threshold++;
3041 b_adaptive.gain_applier_adjacent_speech_frames_threshold =
3042 a_adaptive.gain_applier_adjacent_speech_frames_threshold;
3043 EXPECT_EQ(a, b);
3044
3045 a_adaptive.max_gain_change_db_per_second += 1.f;
3046 b_adaptive.max_gain_change_db_per_second =
3047 a_adaptive.max_gain_change_db_per_second;
3048 EXPECT_EQ(a, b);
3049
3050 a_adaptive.max_output_noise_level_dbfs -= 1.f;
3051 b_adaptive.max_output_noise_level_dbfs =
3052 a_adaptive.max_output_noise_level_dbfs;
3053 EXPECT_EQ(a, b);
3054}
3055
3056// Checks that one differing parameter is sufficient to make two configs
3057// different.
3058TEST(AudioProcessing, GainController2ConfigNotEqual) {
3059 AudioProcessing::Config::GainController2 a;
3060 const AudioProcessing::Config::GainController2 b;
3061
3062 Toggle(a.enabled);
3063 EXPECT_NE(a, b);
3064 a.enabled = b.enabled;
3065
3066 a.fixed_digital.gain_db += 1.f;
3067 EXPECT_NE(a, b);
3068 a.fixed_digital.gain_db = b.fixed_digital.gain_db;
3069
3070 auto& a_adaptive = a.adaptive_digital;
3071 const auto& b_adaptive = b.adaptive_digital;
3072
3073 Toggle(a_adaptive.enabled);
3074 EXPECT_NE(a, b);
3075 a_adaptive.enabled = b_adaptive.enabled;
3076
3077 a_adaptive.vad_probability_attack += 1.f;
3078 EXPECT_NE(a, b);
3079 a_adaptive.vad_probability_attack = b_adaptive.vad_probability_attack;
3080
3081 a_adaptive.level_estimator =
3082 AudioProcessing::Config::GainController2::LevelEstimator::kPeak;
3083 EXPECT_NE(a, b);
3084 a_adaptive.level_estimator = b_adaptive.level_estimator;
3085
3086 a_adaptive.level_estimator_adjacent_speech_frames_threshold++;
3087 EXPECT_NE(a, b);
3088 a_adaptive.level_estimator_adjacent_speech_frames_threshold =
3089 b_adaptive.level_estimator_adjacent_speech_frames_threshold;
3090
3091 Toggle(a_adaptive.use_saturation_protector);
3092 EXPECT_NE(a, b);
3093 a_adaptive.use_saturation_protector = b_adaptive.use_saturation_protector;
3094
3095 a_adaptive.initial_saturation_margin_db += 1.f;
3096 EXPECT_NE(a, b);
3097 a_adaptive.initial_saturation_margin_db =
3098 b_adaptive.initial_saturation_margin_db;
3099
3100 a_adaptive.extra_saturation_margin_db += 1.f;
3101 EXPECT_NE(a, b);
3102 a_adaptive.extra_saturation_margin_db = b_adaptive.extra_saturation_margin_db;
3103
3104 a_adaptive.gain_applier_adjacent_speech_frames_threshold++;
3105 EXPECT_NE(a, b);
3106 a_adaptive.gain_applier_adjacent_speech_frames_threshold =
3107 b_adaptive.gain_applier_adjacent_speech_frames_threshold;
3108
3109 a_adaptive.max_gain_change_db_per_second += 1.f;
3110 EXPECT_NE(a, b);
3111 a_adaptive.max_gain_change_db_per_second =
3112 b_adaptive.max_gain_change_db_per_second;
3113
3114 a_adaptive.max_output_noise_level_dbfs -= 1.f;
3115 EXPECT_NE(a, b);
3116 a_adaptive.max_output_noise_level_dbfs =
3117 b_adaptive.max_output_noise_level_dbfs;
3118}
3119
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003120} // namespace webrtc