blob: b21a0227c51eb35c0c21b4beb56633be7686562d [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
andrew@webrtc.org293d22b2012-01-30 22:04:26 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
Jonas Olssona4d87372019-07-05 19:08:33 +020010#include "modules/audio_processing/include/audio_processing.h"
11
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000012#include <math.h>
ajm@google.com59e41402011-07-28 17:34:04 +000013#include <stdio.h>
kwiberg62eaacf2016-02-17 06:39:05 -080014
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000015#include <algorithm>
Oleh Prypin708eccc2019-03-27 09:38:52 +010016#include <cmath>
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000017#include <limits>
kwiberg62eaacf2016-02-17 06:39:05 -080018#include <memory>
Sam Zackrissone277bde2019-10-25 10:07:54 +020019#include <numeric>
bjornv@webrtc.org3e102492013-02-14 15:29:09 +000020#include <queue>
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000021
Sam Zackrisson6558fa52019-08-26 10:12:41 +020022#include "absl/flags/flag.h"
Sam Zackrisson03cb7e52021-12-06 15:40:04 +010023#include "api/audio/echo_detector_creator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "common_audio/include/audio_util.h"
25#include "common_audio/resampler/include/push_resampler.h"
26#include "common_audio/resampler/push_sinc_resampler.h"
27#include "common_audio/signal_processing/include/signal_processing_library.h"
28#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
29#include "modules/audio_processing/audio_processing_impl.h"
Sam Zackrisson0beac582017-09-25 12:04:02 +020030#include "modules/audio_processing/include/mock_audio_processing.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020031#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020032#include "modules/audio_processing/test/protobuf_utils.h"
33#include "modules/audio_processing/test/test_utils.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/arraysize.h"
35#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "rtc_base/gtest_prod_util.h"
38#include "rtc_base/ignore_wundef.h"
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +010039#include "rtc_base/numerics/safe_conversions.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010040#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020041#include "rtc_base/protobuf_utils.h"
Steve Anton10542f22019-01-11 09:11:00 -080042#include "rtc_base/ref_counted_object.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020043#include "rtc_base/strings/string_builder.h"
Alessio Bazzicac054e782018-04-16 12:10:09 +020044#include "rtc_base/swap_queue.h"
Niels Möllera12c42a2018-07-25 16:05:48 +020045#include "rtc_base/system/arch.h"
Danil Chapovalov07122bc2019-03-26 14:37:01 +010046#include "rtc_base/task_queue_for_test.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020047#include "rtc_base/thread.h"
Per Åhgrena43178c2020-09-25 12:02:32 +020048#include "system_wrappers/include/cpu_features_wrapper.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020049#include "test/gtest.h"
Steve Anton10542f22019-01-11 09:11:00 -080050#include "test/testsupport/file_utils.h"
kwiberg77eab702016-09-28 17:42:01 -070051
52RTC_PUSH_IGNORING_WUNDEF()
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000053#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
leozwang@webrtc.org534e4952012-10-22 21:21:52 +000054#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000055#else
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020056#include "modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:00 +000057#endif
kwiberg77eab702016-09-28 17:42:01 -070058RTC_POP_IGNORING_WUNDEF()
niklase@google.com470e71d2011-07-07 08:21:25 +000059
Sam Zackrisson6558fa52019-08-26 10:12:41 +020060ABSL_FLAG(bool,
61 write_apm_ref_data,
62 false,
63 "Write ApmTest.Process results to file, instead of comparing results "
64 "to the existing reference data file.");
65
andrew@webrtc.org27c69802014-02-18 20:24:56 +000066namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000067namespace {
andrew@webrtc.org17e40642014-03-04 20:58:13 +000068
ekmeyerson60d9b332015-08-14 10:35:55 -070069// TODO(ekmeyerson): Switch to using StreamConfig and ProcessingConfig where
70// applicable.
71
mbonadei7c2c8432017-04-07 00:59:12 -070072const int32_t kChannels[] = {1, 2};
Alejandro Luebs47748742015-05-22 12:00:21 -070073const int kSampleRates[] = {8000, 16000, 32000, 48000};
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +000074
aluebseb3603b2016-04-20 15:27:58 -070075#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
76// Android doesn't support 48kHz.
77const int kProcessSampleRates[] = {8000, 16000, 32000};
78#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Alejandro Luebs47748742015-05-22 12:00:21 -070079const int kProcessSampleRates[] = {8000, 16000, 32000, 48000};
aluebseb3603b2016-04-20 15:27:58 -070080#endif
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +000081
ekmeyerson60d9b332015-08-14 10:35:55 -070082enum StreamDirection { kForward = 0, kReverse };
83
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000084void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 19:08:33 +020085 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
86 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000087 cb_int.channels());
Peter Kasting69558702016-01-12 16:26:35 -080088 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +020089 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +000090 }
andrew@webrtc.orga8b97372014-03-10 22:26:12 +000091}
andrew@webrtc.org17e40642014-03-04 20:58:13 +000092
Per Åhgren2507f8c2020-03-19 12:33:29 +010093void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
94 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +000095}
96
Jonas Olssona4d87372019-07-05 19:08:33 +020097void MixStereoToMono(const float* stereo,
98 float* mono,
pkasting25702cb2016-01-08 13:50:27 -080099 size_t samples_per_channel) {
100 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000101 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000102}
103
Jonas Olssona4d87372019-07-05 19:08:33 +0200104void MixStereoToMono(const int16_t* stereo,
105 int16_t* mono,
pkasting25702cb2016-01-08 13:50:27 -0800106 size_t samples_per_channel) {
107 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000108 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
109}
110
pkasting25702cb2016-01-08 13:50:27 -0800111void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
112 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000113 stereo[i * 2 + 1] = stereo[i * 2];
114 }
115}
116
yujo36b1a5f2017-06-12 12:45:32 -0700117void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 13:50:27 -0800118 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000119 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
120 }
121}
122
Per Åhgren2507f8c2020-03-19 12:33:29 +0100123void SetFrameTo(Int16FrameData* frame, int16_t value) {
124 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700125 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100126 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000127 }
128}
129
Per Åhgren2507f8c2020-03-19 12:33:29 +0100130void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
131 ASSERT_EQ(2u, frame->num_channels);
132 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
133 frame->data[i] = left;
134 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27 +0000135 }
136}
137
Per Åhgren2507f8c2020-03-19 12:33:29 +0100138void ScaleFrame(Int16FrameData* frame, float scale) {
139 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 14:52:23 -0700140 ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100141 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000142 }
143}
144
Per Åhgren2507f8c2020-03-19 12:33:29 +0100145bool FrameDataAreEqual(const Int16FrameData& frame1,
146 const Int16FrameData& frame2) {
147 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000148 return false;
149 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100150 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000151 return false;
152 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100153 if (memcmp(
154 frame1.data.data(), frame2.data.data(),
155 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000156 return false;
157 }
158 return true;
159}
160
Per Åhgren2507f8c2020-03-19 12:33:29 +0100161rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
162 int16_t* ptr = frame->data.data();
163 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200164 return rtc::ArrayView<int16_t>(ptr, len);
165}
166
Per Åhgren2507f8c2020-03-19 12:33:29 +0100167rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
168 const int16_t* ptr = frame.data.data();
169 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200170 return rtc::ArrayView<const int16_t>(ptr, len);
171}
172
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000173void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200174 AudioProcessing::Config apm_config = ap->GetConfig();
175 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000176#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200177 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100178
179 apm_config.gain_controller1.enabled = true;
180 apm_config.gain_controller1.mode =
181 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000182#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 16:26:14 +0200183 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000184
Sam Zackrissonf0d1c032019-03-27 13:28:08 +0100185 apm_config.gain_controller1.enabled = true;
186 apm_config.gain_controller1.mode =
187 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000188#endif
Sam Zackrisson2a959d92018-07-23 14:48:07 +0000189
saza0bad15f2019-10-16 11:46:11 +0200190 apm_config.noise_suppression.enabled = true;
191
peah8271d042016-11-22 07:24:52 -0800192 apm_config.high_pass_filter.enabled = true;
Per Åhgrenc0424252019-12-10 13:04:15 +0100193 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 07:24:52 -0800194 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000195}
196
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +0000197// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000198template <class T>
199T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 19:08:33 +0200200 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000201}
202
Per Åhgren2507f8c2020-03-19 12:33:29 +0100203int16_t MaxAudioFrame(const Int16FrameData& frame) {
204 const size_t length = frame.samples_per_channel * frame.num_channels;
205 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 13:50:27 -0800206 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100207 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16 +0000208 }
209
210 return max_data;
211}
212
Alex Loiko890988c2017-08-31 10:25:48 +0200213void OpenFileAndWriteMessage(const std::string& filename,
mbonadei7c2c8432017-04-07 00:59:12 -0700214 const MessageLite& msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000215 FILE* file = fopen(filename.c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000216 ASSERT_TRUE(file != NULL);
217
Mirko Bonadei5b86f0a2017-11-29 15:20:26 +0100218 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27 +0000219 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 06:39:05 -0800220 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000221 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000222
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000223 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000224 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 19:08:33 +0200225 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27 +0000226 fclose(file);
227}
228
Alex Loiko890988c2017-08-31 10:25:48 +0200229std::string ResourceFilePath(const std::string& name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200230 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000231 // Resource files are all stereo.
232 ss << name << sample_rate_hz / 1000 << "_stereo";
233 return test::ResourcePath(ss.str(), "pcm");
234}
235
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000236// Temporary filenames unique to this process. Used to be able to run these
237// tests in parallel as each process needs to be running in isolation they can't
238// have competing filenames.
239std::map<std::string, std::string> temp_filenames;
240
Alex Loiko890988c2017-08-31 10:25:48 +0200241std::string OutputFilePath(const std::string& name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46 +0000242 int input_rate,
243 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -0700244 int reverse_input_rate,
245 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800246 size_t num_input_channels,
247 size_t num_output_channels,
248 size_t num_reverse_input_channels,
249 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 10:35:55 -0700250 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200251 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 10:35:55 -0700252 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
253 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000254 if (num_output_channels == 1) {
255 ss << "mono";
256 } else if (num_output_channels == 2) {
257 ss << "stereo";
258 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100259 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000260 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700261 ss << output_rate / 1000;
262 if (num_reverse_output_channels == 1) {
263 ss << "_rmono";
264 } else if (num_reverse_output_channels == 2) {
265 ss << "_rstereo";
266 } else {
Artem Titovd3251962021-11-15 16:57:07 +0100267 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 10:35:55 -0700268 }
269 ss << reverse_output_rate / 1000;
270 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000271
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000272 std::string filename = ss.str();
pbosbb36fdf2015-07-09 07:48:14 -0700273 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18 +0000274 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
275 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000276}
277
pbos@webrtc.org200ac002015-02-03 14:14:01 +0000278void ClearTempFiles() {
279 for (auto& kv : temp_filenames)
280 remove(kv.second.c_str());
281}
282
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +0200283// Only remove "out" files. Keep "ref" files.
284void ClearTempOutFiles() {
285 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
286 const std::string& filename = it->first;
287 if (filename.substr(0, 3).compare("out") == 0) {
288 remove(it->second.c_str());
289 temp_filenames.erase(it++);
290 } else {
291 it++;
292 }
293 }
294}
295
Alex Loiko890988c2017-08-31 10:25:48 +0200296void OpenFileAndReadMessage(const std::string& filename, MessageLite* msg) {
andrew@webrtc.org81865342012-10-27 00:28:27 +0000297 FILE* file = fopen(filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000298 ASSERT_TRUE(file != NULL);
299 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27 +0000300 fclose(file);
301}
302
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000303// Reads a 10 ms chunk of int16 interleaved audio from the given (assumed
304// stereo) file, converts to deinterleaved float (optionally downmixing) and
Artem Titov0b489302021-07-28 20:50:03 +0200305// returns the result in `cb`. Returns false if the file ended (or on error) and
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000306// true otherwise.
307//
Artem Titov0b489302021-07-28 20:50:03 +0200308// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000309// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 19:08:33 +0200310bool ReadChunk(FILE* file,
311 int16_t* int_data,
312 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000313 ChannelBuffer<float>* cb) {
314 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000315 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000316 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
317 if (read_count != frame_size) {
318 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 05:23:22 -0700319 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000320 return false; // This is expected.
321 }
322
323 S16ToFloat(int_data, frame_size, float_data);
324 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15 +0000325 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000326 } else {
Jonas Olssona4d87372019-07-05 19:08:33 +0200327 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21 +0000328 }
329
330 return true;
331}
332
Per Åhgrena43178c2020-09-25 12:02:32 +0200333// Returns the reference file name that matches the current CPU
334// architecture/optimizations.
335std::string GetReferenceFilename() {
336#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
337 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
338#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
339 if (GetCPUInfo(kAVX2) != 0) {
340 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
341 }
342 return test::ResourcePath("audio_processing/output_data_float", "pb");
343#endif
344}
345
niklase@google.com470e71d2011-07-07 08:21:25 +0000346class ApmTest : public ::testing::Test {
347 protected:
348 ApmTest();
349 virtual void SetUp();
350 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000351
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200352 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56 +0000353
Mirko Bonadei71061bc2019-06-04 09:01:51 +0200354 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000355
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000356 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 19:08:33 +0200357 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000358
359 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000360 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000361 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800362 size_t num_input_channels,
363 size_t num_output_channels,
364 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000365 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000366 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000367 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 12:33:29 +0100368 bool ReadFrame(FILE* file, Int16FrameData* frame);
369 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
370 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 19:08:33 +0200371 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100372 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000373 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 19:08:33 +0200374 void ProcessDelayVerificationTest(int delay_ms,
375 int system_delay_ms,
376 int delay_min,
377 int delay_max);
Michael Graczyk86c6d332015-07-23 11:41:39 -0700378 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800379 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700380 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800381 void TestChangingForwardChannels(size_t num_in_channels,
382 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700383 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-12 16:26:35 -0800384 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700385 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000386 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
387 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000388 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000389 int ProcessStreamChooser(Format format);
390 int AnalyzeReverseStreamChooser(Format format);
391 void ProcessDebugDump(const std::string& in_filename,
392 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -0800393 Format format,
394 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000395 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000396
397 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000398 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 11:30:54 +0200399 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100400 Int16FrameData frame_;
401 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 15:40:04 +0100402 std::unique_ptr<ChannelBuffer<float>> float_cb_;
403 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000404 int output_sample_rate_hz_;
Peter Kasting69558702016-01-12 16:26:35 -0800405 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000406 FILE* far_file_;
407 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000408 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000409};
410
411ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000412 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 12:02:32 +0200413 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000414 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000415 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01 +0000416 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000417 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000418 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200419 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 13:04:15 +0100420 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +0100421 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 13:04:15 +0100422 apm_config.pipeline.maximum_internal_processing_rate = 48000;
423 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +0000424}
niklase@google.com470e71d2011-07-07 08:21:25 +0000425
426void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32 +0000427 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25 +0000428
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000429 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25 +0000430}
431
432void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25 +0000433 if (far_file_) {
434 ASSERT_EQ(0, fclose(far_file_));
435 }
436 far_file_ = NULL;
437
438 if (near_file_) {
439 ASSERT_EQ(0, fclose(near_file_));
440 }
441 near_file_ = NULL;
442
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000443 if (out_file_) {
444 ASSERT_EQ(0, fclose(out_file_));
445 }
446 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +0000447}
448
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000449void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200450 ASSERT_EQ(
451 kNoErr,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100452 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200453 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100454 {revframe_.sample_rate_hz, revframe_.num_channels},
455 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000456}
457
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000458void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000459 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000460 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-12 16:26:35 -0800461 size_t num_input_channels,
462 size_t num_output_channels,
463 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000464 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200465 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000466 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000467 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000468
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200469 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000470 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000471 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000472
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000473 if (far_file_) {
474 ASSERT_EQ(0, fclose(far_file_));
475 }
476 std::string filename = ResourceFilePath("far", sample_rate_hz);
477 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200478 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000479
480 if (near_file_) {
481 ASSERT_EQ(0, fclose(near_file_));
482 }
483 filename = ResourceFilePath("near", sample_rate_hz);
484 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200485 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000486
487 if (open_output_file) {
488 if (out_file_) {
489 ASSERT_EQ(0, fclose(out_file_));
490 }
ekmeyerson60d9b332015-08-14 10:35:55 -0700491 filename = OutputFilePath(
492 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
493 reverse_sample_rate_hz, num_input_channels, num_output_channels,
494 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000495 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 19:08:33 +0200496 ASSERT_TRUE(out_file_ != NULL)
497 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +0000498 }
499}
500
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000501void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000502 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000503}
504
Jonas Olssona4d87372019-07-05 19:08:33 +0200505bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100506 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000507 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000508 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100509 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 19:08:33 +0200510 size_t read_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100511 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000512 if (read_count != frame_size) {
513 // Check that the file really ended.
514 EXPECT_NE(0, feof(file));
515 return false; // This is expected.
516 }
517
Per Åhgren2507f8c2020-03-19 12:33:29 +0100518 if (frame->num_channels == 1) {
519 MixStereoToMono(frame->data.data(), frame->data.data(),
520 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000521 }
522
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000523 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000524 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000525 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +0000526 return true;
ajm@google.coma769fa52011-07-13 21:57:58 +0000527}
528
Per Åhgren2507f8c2020-03-19 12:33:29 +0100529bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000530 return ReadFrame(file, frame, NULL);
531}
532
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000533// If the end of the file has been reached, rewind it and attempt to read the
534// frame again.
Jonas Olssona4d87372019-07-05 19:08:33 +0200535void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100536 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000537 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200538 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000539 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200540 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000541 }
542}
543
Per Åhgren2507f8c2020-03-19 12:33:29 +0100544void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000545 ReadFrameWithRewind(file, frame, NULL);
546}
547
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000548int ApmTest::ProcessStreamChooser(Format format) {
549 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100550 return apm_->ProcessStream(
551 frame_.data.data(),
552 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
553 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100554 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000555 }
Jonas Olssona4d87372019-07-05 19:08:33 +0200556 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100557 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100558 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100559 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 19:08:33 +0200560 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000561}
562
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000563int ApmTest::AnalyzeReverseStreamChooser(Format format) {
564 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100565 return apm_->ProcessReverseStream(
566 revframe_.data.data(),
567 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
568 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
569 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000570 }
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000571 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +0100572 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 12:33:29 +0100573 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000574}
575
Jonas Olssona4d87372019-07-05 19:08:33 +0200576void ApmTest::ProcessDelayVerificationTest(int delay_ms,
577 int system_delay_ms,
578 int delay_min,
579 int delay_max) {
Artem Titov0b489302021-07-28 20:50:03 +0200580 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000581 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100582 Int16FrameData tmp_frame;
583 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000584 bool causal = true;
585
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200586 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000587 SetFrameTo(&tmp_frame, 0);
588
589 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 20:50:03 +0200590 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000591 int frame_delay = delay_ms / 10;
592 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100593 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000594 frame->CopyFrom(tmp_frame);
595 frame_queue.push(frame);
596 frame_delay++;
597 causal = false;
598 }
599 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100600 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000601 frame->CopyFrom(tmp_frame);
602 frame_queue.push(frame);
603 frame_delay--;
604 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000605 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
606 // need enough frames with audio to have reliable estimates, but as few as
607 // possible to keep processing time down. 4.5 seconds seemed to be a good
608 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000609 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100610 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000611 frame->CopyFrom(tmp_frame);
612 // Use the near end recording, since that has more speech in it.
613 ASSERT_TRUE(ReadFrame(near_file_, frame));
614 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100615 Int16FrameData* reverse_frame = frame;
616 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000617 if (!causal) {
618 reverse_frame = frame_queue.front();
619 // When we call ProcessStream() the frame is modified, so we can't use the
620 // pointer directly when things are non-causal. Use an intermediate frame
621 // and copy the data.
622 process_frame = &tmp_frame;
623 process_frame->CopyFrom(*frame);
624 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100625 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
626 reverse_frame->data.data(),
627 StreamConfig(reverse_frame->sample_rate_hz,
628 reverse_frame->num_channels),
629 StreamConfig(reverse_frame->sample_rate_hz,
630 reverse_frame->num_channels),
631 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000632 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100633 EXPECT_EQ(apm_->kNoError,
634 apm_->ProcessStream(process_frame->data.data(),
635 StreamConfig(process_frame->sample_rate_hz,
636 process_frame->num_channels),
637 StreamConfig(process_frame->sample_rate_hz,
638 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100639 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000640 frame = frame_queue.front();
641 frame_queue.pop();
642 delete frame;
643
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34 +0000644 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000645 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100646 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000647 }
648 }
649
650 rewind(near_file_);
651 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100652 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000653 frame_queue.pop();
654 delete frame;
655 }
656 // Calculate expected delay estimate and acceptable regions. Further,
657 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700658 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 12:33:29 +0100659 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 11:40:47 -0700660 const int expected_median =
661 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
662 const int expected_median_high = rtc::SafeClamp<int>(
663 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700664 delay_max);
kwiberg07038562017-06-12 11:40:47 -0700665 const int expected_median_low = rtc::SafeClamp<int>(
666 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700667 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000668 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 14:32:14 +0100669 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200670 ASSERT_TRUE(stats.delay_median_ms.has_value());
671 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09 +0000672 EXPECT_GE(expected_median_high, median);
673 EXPECT_LE(expected_median_low, median);
674}
675
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000676void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000677 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000678 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000679
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000680 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 10:10:26 +0200681 AudioProcessing::Config apm_config = apm_->GetConfig();
682 apm_config.gain_controller1.enabled = true;
683 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 19:08:33 +0200684 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000685
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000686 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 10:10:26 +0200687 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000688 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 19:08:33 +0200689 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000690
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000691 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +0200692 apm_config.echo_canceller.enabled = true;
693 apm_config.echo_canceller.mobile_mode = false;
694 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000695 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 19:08:33 +0200696 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200697 apm_config.gain_controller1.enabled = false;
698 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000699
700 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000701 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100702 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000703
704 // Resets after successful ProcessStream().
705 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000706 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100707 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000708
709 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200710 apm_config.gain_controller1.enabled = true;
711 apm_->ApplyConfig(apm_config);
712 apm_->set_stream_analog_level(127);
Per Åhgren200feba2019-03-06 04:16:46 +0100713 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200714 apm_config.gain_controller1.enabled = false;
715 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000716
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000717 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 19:08:33 +0200718 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba2019-03-06 04:16:46 +0100719 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25 +0000720
andrew@webrtc.org1e916932011-11-29 18:28:57 +0000721 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 10:10:26 +0200723 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000724 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000725}
726
727TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000728 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13 +0000729}
730
731TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000732 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +0000733}
734
Michael Graczyk86c6d332015-07-23 11:41:39 -0700735void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-12 16:26:35 -0800736 size_t num_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700737 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100738 frame_.num_channels = num_channels;
739
740 EXPECT_EQ(expected_return,
741 apm_->ProcessStream(
742 frame_.data.data(),
743 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
744 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +0100745 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100746 EXPECT_EQ(expected_return,
747 apm_->ProcessReverseStream(
748 frame_.data.data(),
749 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
750 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
751 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000752}
753
Michael Graczyk86c6d332015-07-23 11:41:39 -0700754void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800755 size_t num_in_channels,
756 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700757 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100758 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700759 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
760
761 EXPECT_EQ(expected_return,
762 apm_->ProcessStream(float_cb_->channels(), input_stream,
763 output_stream, float_cb_->channels()));
764}
765
766void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-12 16:26:35 -0800767 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 11:41:39 -0700768 AudioProcessing::Error expected_return) {
769 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100770 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 10:35:55 -0700771 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 12:33:29 +0100772 {frame_.sample_rate_hz, num_rev_channels},
773 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 11:41:39 -0700774
ekmeyerson60d9b332015-08-14 10:35:55 -0700775 EXPECT_EQ(
776 expected_return,
777 apm_->ProcessReverseStream(
778 float_cb_->channels(), processing_config.reverse_input_stream(),
779 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 11:41:39 -0700780}
781
782TEST_F(ApmTest, ChannelsInt16Interface) {
783 // Testing number of invalid and valid channels.
784 Init(16000, 16000, 16000, 4, 4, 4, false);
785
786 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
787
Peter Kasting69558702016-01-12 16:26:35 -0800788 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700789 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25 +0000790 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25 +0000791 }
792}
793
Michael Graczyk86c6d332015-07-23 11:41:39 -0700794TEST_F(ApmTest, Channels) {
795 // Testing number of invalid and valid channels.
796 Init(16000, 16000, 16000, 4, 4, 4, false);
797
798 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
799 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
800
Peter Kasting69558702016-01-12 16:26:35 -0800801 for (size_t i = 1; i < 4; ++i) {
802 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 11:41:39 -0700803 // Output channels much be one or match input channels.
804 if (j == 1 || i == j) {
805 TestChangingForwardChannels(i, j, kNoErr);
806 TestChangingReverseChannels(i, kNoErr);
807
808 EXPECT_EQ(i, apm_->num_input_channels());
809 EXPECT_EQ(j, apm_->num_output_channels());
810 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-12 16:26:35 -0800811 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 11:41:39 -0700812 } else {
813 TestChangingForwardChannels(i, j,
814 AudioProcessing::kBadNumberChannelsError);
815 }
816 }
817 }
818}
819
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000820TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100821 // Testing some valid sample rates.
822 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
823 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +0000824 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +0000825 }
826}
827
Sam Zackrissone277bde2019-10-25 10:07:54 +0200828// This test repeatedly reconfigures the pre-amplifier in APM, processes a
829// number of frames, and checks that output signal has the right level.
830TEST_F(ApmTest, PreAmplifier) {
831 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200832 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100833 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 10:07:54 +0200834 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100835 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200836 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
837 }
838 }
839 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100840 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200841 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200842
Per Åhgren2507f8c2020-03-19 12:33:29 +0100843 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 10:07:54 +0200844 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
845 return std::accumulate(data.begin(), data.end(), 0.0f,
846 [](float a, float b) { return a + b * b; }) /
847 data.size() / 32768 / 32768;
848 };
849
850 const float input_power = compute_power(tmp_frame);
851 // Double-check that the input data is large compared to the error kEpsilon.
852 constexpr float kEpsilon = 1e-4f;
853 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
854
855 // 1. Enable pre-amp with 0 dB gain.
856 AudioProcessing::Config config = apm_->GetConfig();
857 config.pre_amplifier.enabled = true;
858 config.pre_amplifier.fixed_gain_factor = 1.0f;
859 apm_->ApplyConfig(config);
860
861 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200862 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200863 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
864 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200865 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200866 EXPECT_NEAR(output_power, input_power, kEpsilon);
867 config = apm_->GetConfig();
868 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
869
870 // 2. Change pre-amp gain via ApplyConfig.
871 config.pre_amplifier.fixed_gain_factor = 2.0f;
872 apm_->ApplyConfig(config);
873
874 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200875 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200876 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
877 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200878 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200879 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
880 config = apm_->GetConfig();
881 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
882
883 // 3. Change pre-amp gain via a RuntimeSetting.
884 apm_->SetRuntimeSetting(
885 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
886
887 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200888 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200889 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
890 }
Sam Zackrisson70770ac2019-10-25 10:56:53 +0200891 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 10:07:54 +0200892 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
893 config = apm_->GetConfig();
894 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
895}
896
Per Åhgrendb5d7282021-03-15 16:31:04 +0000897// This test a simple test that ensures that the emulated analog mic gain
898// functionality runs without crashing.
899TEST_F(ApmTest, AnalogMicGainEmulation) {
900 // Fill the audio frame with a sawtooth pattern.
901 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
902 const size_t samples_per_channel = frame_.samples_per_channel;
903 for (size_t i = 0; i < samples_per_channel; i++) {
904 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
905 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
906 }
907 }
908 // Cache the frame in tmp_frame.
909 Int16FrameData tmp_frame;
910 tmp_frame.CopyFrom(frame_);
911
912 // Enable the analog gain emulation.
913 AudioProcessing::Config config = apm_->GetConfig();
914 config.capture_level_adjustment.enabled = true;
915 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
916 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
917 config.gain_controller1.enabled = true;
918 config.gain_controller1.mode =
919 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
920 config.gain_controller1.analog_gain_controller.enabled = true;
921 apm_->ApplyConfig(config);
922
923 // Process a number of frames to ensure that the code runs without crashes.
924 for (int i = 0; i < 20; ++i) {
925 frame_.CopyFrom(tmp_frame);
926 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
927 }
928}
929
930// This test repeatedly reconfigures the capture level adjustment functionality
931// in APM, processes a number of frames, and checks that output signal has the
932// right level.
933TEST_F(ApmTest, CaptureLevelAdjustment) {
934 // Fill the audio frame with a sawtooth pattern.
935 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
936 const size_t samples_per_channel = frame_.samples_per_channel;
937 for (size_t i = 0; i < samples_per_channel; i++) {
938 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
939 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
940 }
941 }
942 // Cache the frame in tmp_frame.
943 Int16FrameData tmp_frame;
944 tmp_frame.CopyFrom(frame_);
945
946 auto compute_power = [](const Int16FrameData& frame) {
947 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
948 return std::accumulate(data.begin(), data.end(), 0.0f,
949 [](float a, float b) { return a + b * b; }) /
950 data.size() / 32768 / 32768;
951 };
952
953 const float input_power = compute_power(tmp_frame);
954 // Double-check that the input data is large compared to the error kEpsilon.
955 constexpr float kEpsilon = 1e-20f;
956 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
957
958 // 1. Enable pre-amp with 0 dB gain.
959 AudioProcessing::Config config = apm_->GetConfig();
960 config.capture_level_adjustment.enabled = true;
961 config.capture_level_adjustment.pre_gain_factor = 0.5f;
962 config.capture_level_adjustment.post_gain_factor = 4.f;
963 const float expected_output_power1 =
964 config.capture_level_adjustment.pre_gain_factor *
965 config.capture_level_adjustment.pre_gain_factor *
966 config.capture_level_adjustment.post_gain_factor *
967 config.capture_level_adjustment.post_gain_factor * input_power;
968 apm_->ApplyConfig(config);
969
970 for (int i = 0; i < 20; ++i) {
971 frame_.CopyFrom(tmp_frame);
972 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
973 }
974 float output_power = compute_power(frame_);
975 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
976 config = apm_->GetConfig();
977 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
978 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
979
980 // 2. Change pre-amp gain via ApplyConfig.
981 config.capture_level_adjustment.pre_gain_factor = 1.0f;
982 config.capture_level_adjustment.post_gain_factor = 2.f;
983 const float expected_output_power2 =
984 config.capture_level_adjustment.pre_gain_factor *
985 config.capture_level_adjustment.pre_gain_factor *
986 config.capture_level_adjustment.post_gain_factor *
987 config.capture_level_adjustment.post_gain_factor * input_power;
988 apm_->ApplyConfig(config);
989
990 for (int i = 0; i < 20; ++i) {
991 frame_.CopyFrom(tmp_frame);
992 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
993 }
994 output_power = compute_power(frame_);
995 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
996 config = apm_->GetConfig();
997 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
998 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
999
1000 // 3. Change pre-amp gain via a RuntimeSetting.
1001 constexpr float kPreGain3 = 0.5f;
1002 constexpr float kPostGain3 = 3.f;
1003 const float expected_output_power3 =
1004 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1005
1006 apm_->SetRuntimeSetting(
1007 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1008 apm_->SetRuntimeSetting(
1009 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1010
1011 for (int i = 0; i < 20; ++i) {
1012 frame_.CopyFrom(tmp_frame);
1013 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1014 }
1015 output_power = compute_power(frame_);
1016 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1017 config = apm_->GetConfig();
1018 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1019 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1020}
1021
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57 +00001022TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001023 AudioProcessing::Config config = apm_->GetConfig();
1024 config.gain_controller1.enabled = false;
1025 apm_->ApplyConfig(config);
1026 config.gain_controller1.enabled = true;
1027 apm_->ApplyConfig(config);
1028
niklase@google.com470e71d2011-07-07 08:21:25 +00001029 // Testing gain modes
Sam Zackrisson41478c72019-10-15 10:10:26 +02001030 for (auto mode :
1031 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1032 AudioProcessing::Config::GainController1::kFixedDigital,
1033 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1034 config.gain_controller1.mode = mode;
1035 apm_->ApplyConfig(config);
1036 apm_->set_stream_analog_level(100);
1037 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001038 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001039
Sam Zackrisson41478c72019-10-15 10:10:26 +02001040 // Testing target levels
1041 for (int target_level_dbfs : {0, 15, 31}) {
1042 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1043 apm_->ApplyConfig(config);
1044 apm_->set_stream_analog_level(100);
1045 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001046 }
1047
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001048 // Testing compression gains
Sam Zackrisson41478c72019-10-15 10:10:26 +02001049 for (int compression_gain_db : {0, 10, 90}) {
1050 config.gain_controller1.compression_gain_db = compression_gain_db;
1051 apm_->ApplyConfig(config);
1052 apm_->set_stream_analog_level(100);
1053 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001054 }
1055
1056 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 10:10:26 +02001057 for (bool enable : {false, true}) {
1058 config.gain_controller1.enable_limiter = enable;
1059 apm_->ApplyConfig(config);
1060 apm_->set_stream_analog_level(100);
1061 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1062 }
niklase@google.com470e71d2011-07-07 08:21:25 +00001063
Hanna Silencd597042021-11-02 11:02:48 +01001064 // Testing level limits.
1065 constexpr int kMinLevel = 0;
1066 constexpr int kMaxLevel = 255;
1067 apm_->set_stream_analog_level(kMinLevel);
1068 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1069 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1070 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1071 apm_->set_stream_analog_level(kMaxLevel);
1072 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:25 +00001073}
1074
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001075#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 21:40:37 +02001076using ApmDeathTest = ApmTest;
1077
1078TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001079 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001080 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001081 config.gain_controller1.target_level_dbfs = -1;
1082 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001083}
1084
Tommia5e07cc2020-05-26 21:40:37 +02001085TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001086 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001087 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001088 config.gain_controller1.target_level_dbfs = 32;
1089 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001090}
1091
Tommia5e07cc2020-05-26 21:40:37 +02001092TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001093 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001094 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001095 config.gain_controller1.compression_gain_db = -1;
1096 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001097}
1098
Tommia5e07cc2020-05-26 21:40:37 +02001099TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001100 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001101 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001102 config.gain_controller1.compression_gain_db = 91;
1103 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001104}
1105
Tommia5e07cc2020-05-26 21:40:37 +02001106TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001107 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001108 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001109 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001110 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001111}
1112
Tommia5e07cc2020-05-26 21:40:37 +02001113TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 10:10:26 +02001114 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 14:43:13 +01001115 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 10:10:26 +02001116 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 11:02:48 +01001117 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 13:28:08 +01001118}
1119#endif
1120
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001121void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001122 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001123 auto config = apm_->GetConfig();
1124 config.gain_controller1.enabled = true;
1125 config.gain_controller1.mode =
1126 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1127 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001128
1129 int out_analog_level = 0;
1130 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001131 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001132 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001133 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001134
1135 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 10:10:26 +02001136 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001137 EXPECT_EQ(apm_->kNoError,
1138 apm_->ProcessStream(
1139 frame_.data.data(),
1140 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1141 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001142 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001143 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001144 }
1145
1146 // Ensure the AGC is still able to reach the maximum.
1147 EXPECT_EQ(255, out_analog_level);
1148}
1149
1150// Verifies that despite volume slider quantization, the AGC can continue to
1151// increase its volume.
1152TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
pkasting25702cb2016-01-08 13:50:27 -08001153 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001154 RunQuantizedVolumeDoesNotGetStuckTest(kSampleRates[i]);
1155 }
1156}
1157
1158void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001159 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001160 auto config = apm_->GetConfig();
1161 config.gain_controller1.enabled = true;
1162 config.gain_controller1.mode =
1163 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1164 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001165
1166 int out_analog_level = 100;
1167 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001168 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001169 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001170 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001171
Sam Zackrisson41478c72019-10-15 10:10:26 +02001172 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001173 EXPECT_EQ(apm_->kNoError,
1174 apm_->ProcessStream(
1175 frame_.data.data(),
1176 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1177 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001178 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001179 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001180 }
1181
1182 // Ensure the volume was raised.
1183 EXPECT_GT(out_analog_level, 100);
1184 int highest_level_reached = out_analog_level;
1185 // Simulate a user manual volume change.
1186 out_analog_level = 100;
1187
1188 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001189 ReadFrameWithRewind(near_file_, &frame_);
1190 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001191
Sam Zackrisson41478c72019-10-15 10:10:26 +02001192 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001193 EXPECT_EQ(apm_->kNoError,
1194 apm_->ProcessStream(
1195 frame_.data.data(),
1196 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1197 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001198 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001199 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001200 // Check that AGC respected the manually adjusted volume.
1201 EXPECT_LT(out_analog_level, highest_level_reached);
1202 }
1203 // Check that the volume was still raised.
1204 EXPECT_GT(out_analog_level, 100);
1205}
1206
1207TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
pkasting25702cb2016-01-08 13:50:27 -08001208 for (size_t i = 0; i < arraysize(kSampleRates); ++i) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001209 RunManualVolumeChangeIsPossibleTest(kSampleRates[i]);
1210 }
1211}
1212
niklase@google.com470e71d2011-07-07 08:21:25 +00001213TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:29 +00001214 // Turn HP filter on/off
peah8271d042016-11-22 07:24:52 -08001215 AudioProcessing::Config apm_config;
1216 apm_config.high_pass_filter.enabled = true;
1217 apm_->ApplyConfig(apm_config);
1218 apm_config.high_pass_filter.enabled = false;
1219 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:25 +00001220}
1221
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001222TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001223 AudioProcessing::Config config = apm_->GetConfig();
1224 EXPECT_FALSE(config.echo_canceller.enabled);
1225 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 10:10:26 +02001226 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 11:46:11 +02001227 EXPECT_FALSE(config.noise_suppression.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001228}
1229
1230TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabled) {
pkasting25702cb2016-01-08 13:50:27 -08001231 for (size_t i = 0; i < arraysize(kSampleRates); i++) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001232 Init(kSampleRates[i], kSampleRates[i], kSampleRates[i], 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001233 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001234 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001235 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001236 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001237 EXPECT_EQ(apm_->kNoError,
1238 apm_->ProcessStream(
1239 frame_.data.data(),
1240 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1241 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001242 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001243 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001244 EXPECT_EQ(apm_->kNoError,
1245 apm_->ProcessReverseStream(
1246 frame_.data.data(),
1247 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1248 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1249 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001250 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:10 +00001251 }
1252 }
1253}
1254
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001255TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
1256 // Test that ProcessStream copies input to output even with no processing.
Per Åhgrenc8626b62019-08-23 15:49:51 +02001257 const size_t kSamples = 160;
1258 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 19:08:33 +02001259 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001260 float dest[kSamples] = {};
1261
1262 auto src_channels = &src[0];
1263 auto dest_channels = &dest[0];
1264
Niels Möller4f776ac2021-07-02 11:30:54 +02001265 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001266 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1267 StreamConfig(sample_rate, 1),
1268 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001269
1270 for (size_t i = 0; i < kSamples; ++i) {
1271 EXPECT_EQ(src[i], dest[i]);
1272 }
ekmeyerson60d9b332015-08-14 10:35:55 -07001273
1274 // Same for ProcessReverseStream.
1275 float rev_dest[kSamples] = {};
1276 auto rev_dest_channels = &rev_dest[0];
1277
1278 StreamConfig input_stream = {sample_rate, 1};
1279 StreamConfig output_stream = {sample_rate, 1};
1280 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1281 output_stream, &rev_dest_channels));
1282
1283 for (size_t i = 0; i < kSamples; ++i) {
1284 EXPECT_EQ(src[i], rev_dest[i]);
1285 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:54 +00001286}
1287
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001288TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1289 EnableAllComponents();
1290
pkasting25702cb2016-01-08 13:50:27 -08001291 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001292 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1293 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001294 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001295 ASSERT_EQ(0, feof(far_file_));
1296 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001297 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001298 CopyLeftToRightChannel(revframe_.data.data(),
1299 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001300
Per Åhgren2507f8c2020-03-19 12:33:29 +01001301 ASSERT_EQ(
1302 kNoErr,
1303 apm_->ProcessReverseStream(
1304 revframe_.data.data(),
1305 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1306 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1307 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001308
Per Åhgren2507f8c2020-03-19 12:33:29 +01001309 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001310
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001311 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001312 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001313 ASSERT_EQ(kNoErr,
1314 apm_->ProcessStream(
1315 frame_.data.data(),
1316 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1317 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001318 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001319 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001320
Per Åhgren2507f8c2020-03-19 12:33:29 +01001321 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001322 }
bjornv@webrtc.org3e102492013-02-14 15:29:09 +00001323 rewind(far_file_);
1324 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:00 +00001325 }
1326}
1327
bjornv@webrtc.orgcb0ea432014-06-09 08:21:52 +00001328TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001329 // Verify the filter is not active through undistorted audio when:
1330 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001331 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001332 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001333 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001334 EXPECT_EQ(apm_->kNoError,
1335 apm_->ProcessStream(
1336 frame_.data.data(),
1337 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1338 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001339 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001340 EXPECT_EQ(apm_->kNoError,
1341 apm_->ProcessStream(
1342 frame_.data.data(),
1343 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1344 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001345 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001346 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001347
1348 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 19:31:07 +02001349 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001350 SetFrameTo(&frame_, 1000);
1351 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 19:31:07 +02001352 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001353 EXPECT_EQ(apm_->kNoError,
1354 apm_->ProcessStream(
1355 frame_.data.data(),
1356 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1357 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001358 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001359 EXPECT_EQ(apm_->kNoError,
1360 apm_->ProcessStream(
1361 frame_.data.data(),
1362 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1363 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001364 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001365 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 19:31:07 +02001366 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001367
Sam Zackrissoncb1b5562018-09-28 14:15:09 +02001368 // Check the test is valid. We should have distortion from the filter
1369 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02001370 apm_config.echo_canceller.enabled = true;
1371 apm_config.echo_canceller.mobile_mode = false;
1372 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 12:33:29 +01001373 frame_.samples_per_channel = 320;
1374 frame_.num_channels = 2;
1375 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001376 SetFrameTo(&frame_, 1000);
1377 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001378 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001379 EXPECT_EQ(apm_->kNoError,
1380 apm_->ProcessStream(
1381 frame_.data.data(),
1382 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1383 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001384 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001385 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001386}
1387
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001388#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1389void ApmTest::ProcessDebugDump(const std::string& in_filename,
1390 const std::string& out_filename,
ivocd66b44d2016-01-15 03:06:36 -08001391 Format format,
1392 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001393 TaskQueueForTest worker_queue("ApmTest_worker_queue");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001394 FILE* in_file = fopen(in_filename.c_str(), "rb");
1395 ASSERT_TRUE(in_file != NULL);
1396 audioproc::Event event_msg;
1397 bool first_init = true;
1398
1399 while (ReadMessageFromFile(in_file, &event_msg)) {
1400 if (event_msg.type() == audioproc::Event::INIT) {
1401 const audioproc::Init msg = event_msg.init();
1402 int reverse_sample_rate = msg.sample_rate();
1403 if (msg.has_reverse_sample_rate()) {
1404 reverse_sample_rate = msg.reverse_sample_rate();
1405 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001406 int output_sample_rate = msg.sample_rate();
1407 if (msg.has_output_sample_rate()) {
1408 output_sample_rate = msg.output_sample_rate();
1409 }
1410
Jonas Olssona4d87372019-07-05 19:08:33 +02001411 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1412 msg.num_input_channels(), msg.num_output_channels(),
1413 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001414 if (first_init) {
aleloif4dd1912017-06-15 01:55:38 -07001415 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001416 // recording until after the first init to avoid the extra message.
aleloif4dd1912017-06-15 01:55:38 -07001417 auto aec_dump =
1418 AecDumpFactory::Create(out_filename, max_size_bytes, &worker_queue);
1419 EXPECT_TRUE(aec_dump);
1420 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001421 first_init = false;
1422 }
1423
1424 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1425 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1426
1427 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001428 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001429 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001430 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001431 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1432 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001433 }
1434 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001435 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001436 if (format == kFloatFormat) {
1437 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001438 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001439 }
1440 }
1441 AnalyzeReverseStreamChooser(format);
1442
1443 } else if (event_msg.type() == audioproc::Event::STREAM) {
1444 const audioproc::Stream msg = event_msg.stream();
1445 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001446 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001447
Sam Zackrisson41478c72019-10-15 10:10:26 +02001448 apm_->set_stream_analog_level(msg.level());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001449 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001450 if (msg.has_keypress()) {
1451 apm_->set_stream_key_pressed(msg.keypress());
1452 } else {
1453 apm_->set_stream_key_pressed(true);
1454 }
1455
1456 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001457 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-12 16:26:35 -08001458 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001459 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 19:08:33 +02001460 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1461 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001462 }
1463 } else {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001464 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 12:45:32 -07001465 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001466 if (format == kFloatFormat) {
1467 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001468 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001469 }
1470 }
1471 ProcessStreamChooser(format);
1472 }
1473 }
aleloif4dd1912017-06-15 01:55:38 -07001474 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001475 fclose(in_file);
1476}
1477
1478void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 15:38:52 +02001479 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001480 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:49 +00001481 std::string format_string;
1482 switch (format) {
1483 case kIntFormat:
1484 format_string = "_int";
1485 break;
1486 case kFloatFormat:
1487 format_string = "_float";
1488 break;
1489 }
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001490 const std::string ref_filename = test::TempFilename(
1491 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1492 const std::string out_filename = test::TempFilename(
1493 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 03:06:36 -08001494 const std::string limited_filename = test::TempFilename(
1495 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1496 const size_t logging_limit_bytes = 100000;
1497 // We expect at least this many bytes in the created logfile.
1498 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001499 EnableAllComponents();
ivocd66b44d2016-01-15 03:06:36 -08001500 ProcessDebugDump(in_filename, ref_filename, format, -1);
1501 ProcessDebugDump(ref_filename, out_filename, format, -1);
1502 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001503
1504 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1505 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 03:06:36 -08001506 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001507 ASSERT_TRUE(ref_file != NULL);
1508 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 03:06:36 -08001509 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 06:39:05 -08001510 std::unique_ptr<uint8_t[]> ref_bytes;
1511 std::unique_ptr<uint8_t[]> out_bytes;
1512 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001513
1514 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1515 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001516 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001517 size_t bytes_read = 0;
ivocd66b44d2016-01-15 03:06:36 -08001518 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001519 while (ref_size > 0 && out_size > 0) {
1520 bytes_read += ref_size;
ivocd66b44d2016-01-15 03:06:36 -08001521 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001522 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 03:06:36 -08001523 EXPECT_GE(ref_size, limited_size);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001524 EXPECT_EQ(0, memcmp(ref_bytes.get(), out_bytes.get(), ref_size));
ivocd66b44d2016-01-15 03:06:36 -08001525 EXPECT_EQ(0, memcmp(ref_bytes.get(), limited_bytes.get(), limited_size));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001526 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1527 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 03:06:36 -08001528 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001529 }
1530 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 03:06:36 -08001531 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1532 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001533 EXPECT_NE(0, feof(ref_file));
1534 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001535 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001536 ASSERT_EQ(0, fclose(ref_file));
1537 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 03:06:36 -08001538 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 10:44:11 +02001539 remove(ref_filename.c_str());
1540 remove(out_filename.c_str());
ivocd66b44d2016-01-15 03:06:36 -08001541 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001542}
1543
pbosc7a65692016-05-06 12:50:04 -07001544TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001545 VerifyDebugDumpTest(kIntFormat);
1546}
1547
pbosc7a65692016-05-06 12:50:04 -07001548TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001549 VerifyDebugDumpTest(kFloatFormat);
1550}
1551#endif
1552
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001553// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001554TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001555 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001556 const std::string filename =
1557 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 01:55:38 -07001558 {
1559 auto aec_dump = AecDumpFactory::Create("", -1, &worker_queue);
1560 EXPECT_FALSE(aec_dump);
1561 }
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001562
1563#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1564 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001565 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001566
aleloif4dd1912017-06-15 01:55:38 -07001567 auto aec_dump = AecDumpFactory::Create(filename, -1, &worker_queue);
1568 EXPECT_TRUE(aec_dump);
1569 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001570 EXPECT_EQ(apm_->kNoError,
1571 apm_->ProcessStream(
1572 frame_.data.data(),
1573 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1574 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001575 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001576 EXPECT_EQ(apm_->kNoError,
1577 apm_->ProcessReverseStream(
1578 revframe_.data.data(),
1579 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1580 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1581 revframe_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001582 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001583
1584 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001585 FILE* fid = fopen(filename.c_str(), "r");
1586 ASSERT_TRUE(fid != NULL);
1587
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001588 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:39 +00001589 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001590 ASSERT_EQ(0, remove(filename.c_str()));
1591#else
andrew@webrtc.org7bf26462011-12-03 00:03:31 +00001592 // Verify the file has NOT been written.
1593 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1594#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1595}
1596
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001597// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 12:50:04 -07001598TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 14:37:01 +01001599 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 01:55:38 -07001600
pbos@webrtc.orga525c982015-01-12 17:31:18 +00001601 const std::string filename =
1602 test::TempFilename(test::OutputPath(), "debug_aec");
Niels Möllere8e4dc42019-06-11 14:04:16 +02001603 FileWrapper f = FileWrapper::OpenWriteOnly(filename.c_str());
1604 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001605
1606#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1607 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 01:55:38 -07001608 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001609
Niels Möllere8e4dc42019-06-11 14:04:16 +02001610 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, &worker_queue);
aleloif4dd1912017-06-15 01:55:38 -07001611 EXPECT_TRUE(aec_dump);
1612 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 12:33:29 +01001613 EXPECT_EQ(apm_->kNoError,
1614 apm_->ProcessReverseStream(
1615 revframe_.data.data(),
1616 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1617 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1618 revframe_.data.data()));
1619 EXPECT_EQ(apm_->kNoError,
1620 apm_->ProcessStream(
1621 frame_.data.data(),
1622 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1623 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001624 frame_.data.data()));
aleloif4dd1912017-06-15 01:55:38 -07001625 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001626
1627 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 14:04:16 +02001628 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001629 ASSERT_TRUE(fid != NULL);
1630
1631 // Clean it up.
1632 ASSERT_EQ(0, fclose(fid));
1633 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:17 +00001634#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1635}
1636
andrew@webrtc.org75f19482012-02-09 17:16:18 +00001637// TODO(andrew): Add a test to process a few frames with different combinations
1638// of enabled components.
1639
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001640TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001641 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001642 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001643
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001644 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001645 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001646 } else {
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001647 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 13:50:27 -08001648 for (size_t i = 0; i < arraysize(kChannels); i++) {
1649 for (size_t j = 0; j < arraysize(kChannels); j++) {
1650 for (size_t l = 0; l < arraysize(kProcessSampleRates); l++) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001651 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001652 test->set_num_reverse_channels(kChannels[i]);
1653 test->set_num_input_channels(kChannels[j]);
1654 test->set_num_output_channels(kChannels[j]);
1655 test->set_sample_rate(kProcessSampleRates[l]);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001656 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001657 }
1658 }
1659 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001660#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1661 // To test the extended filter mode.
1662 audioproc::Test* test = ref_data.add_test();
1663 test->set_num_reverse_channels(2);
1664 test->set_num_input_channels(2);
1665 test->set_num_output_channels(2);
1666 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1667 test->set_use_aec_extended_filter(true);
1668#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001669 }
1670
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001671 for (int i = 0; i < ref_data.test_size(); i++) {
1672 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001673
andrew@webrtc.org27c69802014-02-18 20:24:56 +00001674 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001675 // TODO(ajm): We no longer allow different input and output channels. Skip
1676 // these tests for now, but they should be removed from the set.
1677 if (test->num_input_channels() != test->num_output_channels())
1678 continue;
1679
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01001680 apm_ = AudioProcessingBuilderForTesting()
1681 .SetEchoDetector(CreateEchoDetector())
1682 .Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001683 AudioProcessing::Config apm_config = apm_->GetConfig();
1684 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1685 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:53 +00001686
1687 EnableAllComponents();
1688
Jonas Olssona4d87372019-07-05 19:08:33 +02001689 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-12 16:26:35 -08001690 static_cast<size_t>(test->num_input_channels()),
1691 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 19:08:33 +02001692 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001693
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001694 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001695 int analog_level = 127;
1696 int analog_level_average = 0;
1697 int max_output_average = 0;
minyue58530ed2016-05-24 05:50:12 -07001698#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 19:08:33 +02001699 int stats_index = 0;
minyue58530ed2016-05-24 05:50:12 -07001700#endif
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001701
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001702 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01001703 EXPECT_EQ(
1704 apm_->kNoError,
1705 apm_->ProcessReverseStream(
1706 revframe_.data.data(),
1707 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1708 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1709 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001710
1711 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001712 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001713
Per Åhgren2507f8c2020-03-19 12:33:29 +01001714 EXPECT_EQ(apm_->kNoError,
1715 apm_->ProcessStream(
1716 frame_.data.data(),
1717 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1718 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01001719 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:13 +00001720
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001721 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-12 16:26:35 -08001722 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01001723 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001724
Sam Zackrisson70770ac2019-10-25 10:56:53 +02001725 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001726
Sam Zackrisson41478c72019-10-15 10:10:26 +02001727 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001728 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 14:32:14 +01001729 AudioProcessingStats stats = apm_->GetStatistics();
bjornv@webrtc.org08329f42012-07-12 21:00:43 +00001730
Per Åhgren2507f8c2020-03-19 12:33:29 +01001731 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 19:08:33 +02001732 size_t write_count =
Per Åhgren2507f8c2020-03-19 12:33:29 +01001733 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:04 +00001734 ASSERT_EQ(frame_size, write_count);
1735
1736 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 12:33:29 +01001737 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001738 frame_count++;
minyue58530ed2016-05-24 05:50:12 -07001739
1740#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1741 const int kStatsAggregationFrameNum = 100; // 1 second.
1742 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001743 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001744 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 05:50:12 -07001745
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001746 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001747 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001748 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001749 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001750 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001751 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001752 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 11:26:11 +02001753 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001754
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001755 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 05:50:12 -07001756 const audioproc::Test::EchoMetrics& reference =
1757 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001758 constexpr float kEpsilon = 0.01;
1759 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1760 EXPECT_NEAR(echo_return_loss_enhancement,
1761 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001762 EXPECT_NEAR(residual_echo_likelihood,
1763 reference.residual_echo_likelihood(), kEpsilon);
1764 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1765 reference.residual_echo_likelihood_recent_max(),
1766 kEpsilon);
minyue58530ed2016-05-24 05:50:12 -07001767 ++stats_index;
1768 } else {
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001769 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1770 message_echo->set_echo_return_loss(echo_return_loss);
1771 message_echo->set_echo_return_loss_enhancement(
1772 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 12:59:09 +02001773 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1774 message_echo->set_residual_echo_likelihood_recent_max(
1775 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 05:50:12 -07001776 }
1777 }
1778#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001779 }
1780 max_output_average /= frame_count;
1781 analog_level_average /= frame_count;
1782
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001783 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001784 const int kIntNear = 1;
Alessio Bazzica1db0a262022-02-15 14:18:09 +00001785 // All numbers being consistently higher on N7 compare to the reference
1786 // data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001787 // TODO(bjornv): If we start getting more of these offsets on Android we
1788 // should consider a different approach. Either using one slack for all,
1789 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 15:29:45 +02001790#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001791 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 15:22:50 +02001792 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001793#else
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001794 const int kMaxOutputAverageOffset = 0;
1795 const int kMaxOutputAverageNear = kIntNear;
1796#endif
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35 +00001797 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:44 +00001798 EXPECT_NEAR(test->max_output_average(),
1799 max_output_average - kMaxOutputAverageOffset,
1800 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001801 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001802 test->set_analog_level_average(analog_level_average);
1803 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001804 }
1805
1806 rewind(far_file_);
1807 rewind(near_file_);
1808 }
1809
Sam Zackrisson6558fa52019-08-26 10:12:41 +02001810 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:12 +00001811 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:56 +00001812 }
1813}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001814
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001815// Compares the reference and test arrays over a region around the expected
1816// delay. Finds the highest SNR in that region and adds the variance and squared
1817// error results to the supplied accumulators.
1818void UpdateBestSNR(const float* ref,
1819 const float* test,
pkasting25702cb2016-01-08 13:50:27 -08001820 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001821 int expected_delay,
1822 double* variance_acc,
1823 double* sq_error_acc) {
1824 double best_snr = std::numeric_limits<double>::min();
1825 double best_variance = 0;
1826 double best_sq_error = 0;
1827 // Search over a region of eight samples around the expected delay.
1828 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1829 ++delay) {
1830 double sq_error = 0;
1831 double variance = 0;
pkasting25702cb2016-01-08 13:50:27 -08001832 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001833 double error = test[i + delay] - ref[i];
1834 sq_error += error * error;
1835 variance += ref[i] * ref[i];
1836 }
1837
1838 if (sq_error == 0) {
1839 *variance_acc += variance;
1840 return;
1841 }
1842 double snr = variance / sq_error;
1843 if (snr > best_snr) {
1844 best_snr = snr;
1845 best_variance = variance;
1846 best_sq_error = sq_error;
1847 }
1848 }
1849
1850 *variance_acc += best_variance;
1851 *sq_error_acc += best_sq_error;
1852}
1853
1854// Used to test a multitude of sample rate and channel combinations. It works
1855// by first producing a set of reference files (in SetUpTestCase) that are
1856// assumed to be correct, as the used parameters are verified by other tests
1857// in this collection. Primarily the reference files are all produced at
1858// "native" rates which do not involve any resampling.
1859
1860// Each test pass produces an output file with a particular format. The output
1861// is matched against the reference file closest to its internal processing
1862// format. If necessary the output is resampled back to its process format.
1863// Due to the resampling distortion, we don't expect identical results, but
1864// enforce SNR thresholds which vary depending on the format. 0 is a special
1865// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 23:33:04 +02001866typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001867class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001868 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001869 public:
1870 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 23:33:04 +02001871 : input_rate_(std::get<0>(GetParam())),
1872 output_rate_(std::get<1>(GetParam())),
1873 reverse_input_rate_(std::get<2>(GetParam())),
1874 reverse_output_rate_(std::get<3>(GetParam())),
1875 expected_snr_(std::get<4>(GetParam())),
1876 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001877
1878 virtual ~AudioProcessingTest() {}
1879
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001880 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001881 // Create all needed output reference files.
Alejandro Luebs47748742015-05-22 12:00:21 -07001882 const int kNativeRates[] = {8000, 16000, 32000, 48000};
Peter Kasting69558702016-01-12 16:26:35 -08001883 const size_t kNumChannels[] = {1, 2};
pkasting25702cb2016-01-08 13:50:27 -08001884 for (size_t i = 0; i < arraysize(kNativeRates); ++i) {
1885 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1886 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001887 // The reference files always have matching input and output channels.
ekmeyerson60d9b332015-08-14 10:35:55 -07001888 ProcessFormat(kNativeRates[i], kNativeRates[i], kNativeRates[i],
1889 kNativeRates[i], kNumChannels[j], kNumChannels[j],
1890 kNumChannels[k], kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001891 }
1892 }
1893 }
1894 }
1895
Gustaf Ullberg8ffeeb22017-10-11 11:42:38 +02001896 void TearDown() {
1897 // Remove "out" files after each test.
1898 ClearTempOutFiles();
1899 }
1900
Mirko Bonadei71061bc2019-06-04 09:01:51 +02001901 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 10:35:55 -07001902
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001903 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 20:50:03 +02001904 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 10:35:55 -07001905 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001906 static void ProcessFormat(int input_rate,
1907 int output_rate,
ekmeyerson60d9b332015-08-14 10:35:55 -07001908 int reverse_input_rate,
1909 int reverse_output_rate,
Peter Kasting69558702016-01-12 16:26:35 -08001910 size_t num_input_channels,
1911 size_t num_output_channels,
1912 size_t num_reverse_input_channels,
1913 size_t num_reverse_output_channels,
Alex Loiko890988c2017-08-31 10:25:48 +02001914 const std::string& output_file_prefix) {
Niels Möller4f776ac2021-07-02 11:30:54 +02001915 rtc::scoped_refptr<AudioProcessing> ap =
1916 AudioProcessingBuilderForTesting().Create();
Per Åhgren0695df12020-01-13 14:43:13 +01001917 AudioProcessing::Config apm_config = ap->GetConfig();
1918 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1919 ap->ApplyConfig(apm_config);
1920
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001921 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001922
ekmeyerson60d9b332015-08-14 10:35:55 -07001923 ProcessingConfig processing_config = {
1924 {{input_rate, num_input_channels},
1925 {output_rate, num_output_channels},
1926 {reverse_input_rate, num_reverse_input_channels},
1927 {reverse_output_rate, num_reverse_output_channels}}};
1928 ap->Initialize(processing_config);
1929
1930 FILE* far_file =
1931 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001932 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 19:08:33 +02001933 FILE* out_file = fopen(
1934 OutputFilePath(
1935 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1936 reverse_output_rate, num_input_channels, num_output_channels,
1937 num_reverse_input_channels, num_reverse_output_channels, kForward)
1938 .c_str(),
1939 "wb");
1940 FILE* rev_out_file = fopen(
1941 OutputFilePath(
1942 output_file_prefix, input_rate, output_rate, reverse_input_rate,
1943 reverse_output_rate, num_input_channels, num_output_channels,
1944 num_reverse_input_channels, num_reverse_output_channels, kReverse)
1945 .c_str(),
1946 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001947 ASSERT_TRUE(far_file != NULL);
1948 ASSERT_TRUE(near_file != NULL);
1949 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 10:35:55 -07001950 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001951
1952 ChannelBuffer<float> fwd_cb(SamplesFromRate(input_rate),
1953 num_input_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07001954 ChannelBuffer<float> rev_cb(SamplesFromRate(reverse_input_rate),
1955 num_reverse_input_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001956 ChannelBuffer<float> out_cb(SamplesFromRate(output_rate),
1957 num_output_channels);
ekmeyerson60d9b332015-08-14 10:35:55 -07001958 ChannelBuffer<float> rev_out_cb(SamplesFromRate(reverse_output_rate),
1959 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001960
1961 // Temporary buffers.
1962 const int max_length =
ekmeyerson60d9b332015-08-14 10:35:55 -07001963 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
1964 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 06:39:05 -08001965 std::unique_ptr<float[]> float_data(new float[max_length]);
1966 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001967
1968 int analog_level = 127;
1969 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
1970 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 10:35:55 -07001971 EXPECT_NOERR(ap->ProcessReverseStream(
1972 rev_cb.channels(), processing_config.reverse_input_stream(),
1973 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001974
1975 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 10:10:26 +02001976 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001977
1978 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 09:30:44 +01001979 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
1980 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001981
ekmeyerson60d9b332015-08-14 10:35:55 -07001982 // Dump forward output to file.
1983 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001984 float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08001985 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07001986
Jonas Olssona4d87372019-07-05 19:08:33 +02001987 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
1988 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00001989
ekmeyerson60d9b332015-08-14 10:35:55 -07001990 // Dump reverse output to file.
1991 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
1992 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 13:50:27 -08001993 size_t rev_out_length =
1994 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 10:35:55 -07001995
Jonas Olssona4d87372019-07-05 19:08:33 +02001996 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
1997 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 10:35:55 -07001998
Sam Zackrisson41478c72019-10-15 10:10:26 +02001999 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002000 }
2001 fclose(far_file);
2002 fclose(near_file);
2003 fclose(out_file);
ekmeyerson60d9b332015-08-14 10:35:55 -07002004 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002005 }
2006
2007 protected:
2008 int input_rate_;
2009 int output_rate_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002010 int reverse_input_rate_;
2011 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002012 double expected_snr_;
ekmeyerson60d9b332015-08-14 10:35:55 -07002013 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002014};
2015
bjornv@webrtc.org2812b592014-06-02 11:27:29 +00002016TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002017 struct ChannelFormat {
2018 int num_input;
2019 int num_output;
ekmeyerson60d9b332015-08-14 10:35:55 -07002020 int num_reverse_input;
2021 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002022 };
2023 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 19:08:33 +02002024 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2025 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002026 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002027
pkasting25702cb2016-01-08 13:50:27 -08002028 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 10:35:55 -07002029 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2030 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2031 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 12:00:21 -07002032
ekmeyerson60d9b332015-08-14 10:35:55 -07002033 // Verify output for both directions.
2034 std::vector<StreamDirection> stream_directions;
2035 stream_directions.push_back(kForward);
2036 stream_directions.push_back(kReverse);
2037 for (StreamDirection file_direction : stream_directions) {
2038 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2039 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2040 const int out_num =
2041 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2042 const double expected_snr =
2043 file_direction ? expected_reverse_snr_ : expected_snr_;
2044
2045 const int min_ref_rate = std::min(in_rate, out_rate);
2046 int ref_rate;
2047
2048 if (min_ref_rate > 32000) {
2049 ref_rate = 48000;
2050 } else if (min_ref_rate > 16000) {
2051 ref_rate = 32000;
2052 } else if (min_ref_rate > 8000) {
2053 ref_rate = 16000;
2054 } else {
2055 ref_rate = 8000;
2056 }
Per Åhgrenc0424252019-12-10 13:04:15 +01002057
ekmeyerson60d9b332015-08-14 10:35:55 -07002058 FILE* out_file = fopen(
2059 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2060 reverse_output_rate_, cf[i].num_input,
2061 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 19:08:33 +02002062 cf[i].num_reverse_output, file_direction)
2063 .c_str(),
ekmeyerson60d9b332015-08-14 10:35:55 -07002064 "rb");
2065 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 19:08:33 +02002066 FILE* ref_file =
2067 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2068 cf[i].num_output, cf[i].num_output,
2069 cf[i].num_reverse_output,
2070 cf[i].num_reverse_output, file_direction)
2071 .c_str(),
2072 "rb");
ekmeyerson60d9b332015-08-14 10:35:55 -07002073 ASSERT_TRUE(out_file != NULL);
2074 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002075
pkasting25702cb2016-01-08 13:50:27 -08002076 const size_t ref_length = SamplesFromRate(ref_rate) * out_num;
2077 const size_t out_length = SamplesFromRate(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 10:35:55 -07002078 // Data from the reference file.
kwiberg62eaacf2016-02-17 06:39:05 -08002079 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002080 // Data from the output file.
kwiberg62eaacf2016-02-17 06:39:05 -08002081 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 10:35:55 -07002082 // Data from the resampled output, in case the reference and output rates
2083 // don't match.
kwiberg62eaacf2016-02-17 06:39:05 -08002084 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002085
ekmeyerson60d9b332015-08-14 10:35:55 -07002086 PushResampler<float> resampler;
2087 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002088
ekmeyerson60d9b332015-08-14 10:35:55 -07002089 // Compute the resampling delay of the output relative to the reference,
2090 // to find the region over which we should search for the best SNR.
2091 float expected_delay_sec = 0;
2092 if (in_rate != ref_rate) {
2093 // Input resampling delay.
2094 expected_delay_sec +=
2095 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2096 }
2097 if (out_rate != ref_rate) {
2098 // Output resampling delay.
2099 expected_delay_sec +=
2100 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2101 // Delay of converting the output back to its processing rate for
2102 // testing.
2103 expected_delay_sec +=
2104 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2105 }
2106 int expected_delay =
Oleh Prypin708eccc2019-03-27 09:38:52 +01002107 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002108
ekmeyerson60d9b332015-08-14 10:35:55 -07002109 double variance = 0;
2110 double sq_error = 0;
2111 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2112 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2113 float* out_ptr = out_data.get();
2114 if (out_rate != ref_rate) {
2115 // Resample the output back to its internal processing rate if
2116 // necssary.
pkasting25702cb2016-01-08 13:50:27 -08002117 ASSERT_EQ(ref_length,
2118 static_cast<size_t>(resampler.Resample(
2119 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 10:35:55 -07002120 out_ptr = cmp_data.get();
2121 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002122
Artem Titov0b489302021-07-28 20:50:03 +02002123 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 10:35:55 -07002124 // SNR of reference vs output.
2125 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2126 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002127 }
2128
ekmeyerson60d9b332015-08-14 10:35:55 -07002129 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2130 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2131 << cf[i].num_input << ", " << cf[i].num_output << ", "
2132 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2133 << ", " << file_direction << "): ";
2134 if (sq_error > 0) {
2135 double snr = 10 * log10(variance / sq_error);
2136 EXPECT_GE(snr, expected_snr);
2137 EXPECT_NE(0, expected_snr);
2138 std::cout << "SNR=" << snr << " dB" << std::endl;
2139 } else {
aluebs776593b2016-03-15 14:04:58 -07002140 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 10:35:55 -07002141 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002142
ekmeyerson60d9b332015-08-14 10:35:55 -07002143 fclose(out_file);
2144 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002145 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002146 }
2147}
2148
2149#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002150INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002151 CommonFormats,
2152 AudioProcessingTest,
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002153 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2154 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2155 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2156 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2157 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2158 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2159 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2160 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2161 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2162 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2163 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2164 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002165
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002166 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2167 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2168 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2169 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2170 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2171 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2172 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2173 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2174 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2175 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2176 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2177 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002178
Per Åhgrenc0424252019-12-10 13:04:15 +01002179 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2180 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2181 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002182 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2183 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2184 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2185 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2186 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002187 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002188 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2189 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2190 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 12:00:21 -07002191
Per Åhgrenc0424252019-12-10 13:04:15 +01002192 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2193 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2194 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002195 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2196 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2197 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2198 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2199 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2200 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2201 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 13:03:14 +01002202 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002203 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
Alejandro Luebs47748742015-05-22 12:00:21 -07002204
2205#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 12:20:57 +01002206INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 10:35:55 -07002207 CommonFormats,
2208 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 21:29:17 +02002209 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2210 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2211 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002212 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2213 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2214 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002215 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2216 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2217 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002218 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2219 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2220 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002221
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002222 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2223 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2224 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2225 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2226 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2227 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 21:29:17 +02002228 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2229 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2230 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2231 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2232 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2233 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002234
Per Åhgrenc0424252019-12-10 13:04:15 +01002235 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2236 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2237 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002238 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2239 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2240 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002241 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002242 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002243 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002244 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2245 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2246 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002247
Per Åhgrenc0424252019-12-10 13:04:15 +01002248 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2249 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2250 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002251 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2252 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2253 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 22:59:44 +01002254 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002255 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002256 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 18:22:04 +01002257 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2258 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002259 std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:04 +00002260#endif
2261
Per Åhgren3e8bf282019-08-29 23:38:40 +02002262// Produces a scoped trace debug output.
2263std::string ProduceDebugText(int render_input_sample_rate_hz,
2264 int render_output_sample_rate_hz,
2265 int capture_input_sample_rate_hz,
2266 int capture_output_sample_rate_hz,
2267 size_t render_input_num_channels,
2268 size_t render_output_num_channels,
2269 size_t capture_input_num_channels,
2270 size_t capture_output_num_channels) {
2271 rtc::StringBuilder ss;
2272 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002273 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002274 << render_input_sample_rate_hz
2275 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002276 "\n Render output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002277 << render_output_sample_rate_hz
2278 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002279 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002280 << capture_input_sample_rate_hz
2281 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002282 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002283 << capture_output_sample_rate_hz
2284 << " Hz"
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002285 "\nNumber of channels:"
2286 "\n Render input: "
Jonas Olssonb2b20312020-01-14 12:11:31 +01002287 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 15:54:35 +01002288 << "\n Render output: " << render_output_num_channels
2289 << "\n Capture input: " << capture_input_num_channels
2290 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 23:38:40 +02002291 return ss.Release();
2292}
2293
2294// Validates that running the audio processing module using various combinations
2295// of sample rates and number of channels works as intended.
2296void RunApmRateAndChannelTest(
2297 rtc::ArrayView<const int> sample_rates_hz,
2298 rtc::ArrayView<const int> render_channel_counts,
2299 rtc::ArrayView<const int> capture_channel_counts) {
Niels Möller4f776ac2021-07-02 11:30:54 +02002300 rtc::scoped_refptr<AudioProcessing> apm =
2301 AudioProcessingBuilderForTesting().Create();
Per Åhgren3e8bf282019-08-29 23:38:40 +02002302 webrtc::AudioProcessing::Config apm_config;
2303 apm_config.echo_canceller.enabled = true;
2304 apm->ApplyConfig(apm_config);
2305
2306 StreamConfig render_input_stream_config;
2307 StreamConfig render_output_stream_config;
2308 StreamConfig capture_input_stream_config;
2309 StreamConfig capture_output_stream_config;
2310
2311 std::vector<float> render_input_frame_channels;
2312 std::vector<float*> render_input_frame;
2313 std::vector<float> render_output_frame_channels;
2314 std::vector<float*> render_output_frame;
2315 std::vector<float> capture_input_frame_channels;
2316 std::vector<float*> capture_input_frame;
2317 std::vector<float> capture_output_frame_channels;
2318 std::vector<float*> capture_output_frame;
2319
2320 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2321 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2322 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2323 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2324 for (size_t render_input_num_channels : render_channel_counts) {
2325 for (size_t capture_input_num_channels : capture_channel_counts) {
2326 size_t render_output_num_channels = render_input_num_channels;
2327 size_t capture_output_num_channels = capture_input_num_channels;
2328 auto populate_audio_frame = [](int sample_rate_hz,
2329 size_t num_channels,
2330 StreamConfig* cfg,
2331 std::vector<float>* channels_data,
2332 std::vector<float*>* frame_data) {
2333 cfg->set_sample_rate_hz(sample_rate_hz);
2334 cfg->set_num_channels(num_channels);
Per Åhgren3e8bf282019-08-29 23:38:40 +02002335
2336 size_t max_frame_size = ceil(sample_rate_hz / 100.f);
2337 channels_data->resize(num_channels * max_frame_size);
2338 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2339 frame_data->resize(num_channels);
2340 for (size_t channel = 0; channel < num_channels; ++channel) {
2341 (*frame_data)[channel] =
2342 &(*channels_data)[channel * max_frame_size];
2343 }
2344 };
2345
2346 populate_audio_frame(
2347 render_input_sample_rate_hz, render_input_num_channels,
2348 &render_input_stream_config, &render_input_frame_channels,
2349 &render_input_frame);
2350 populate_audio_frame(
2351 render_output_sample_rate_hz, render_output_num_channels,
2352 &render_output_stream_config, &render_output_frame_channels,
2353 &render_output_frame);
2354 populate_audio_frame(
2355 capture_input_sample_rate_hz, capture_input_num_channels,
2356 &capture_input_stream_config, &capture_input_frame_channels,
2357 &capture_input_frame);
2358 populate_audio_frame(
2359 capture_output_sample_rate_hz, capture_output_num_channels,
2360 &capture_output_stream_config, &capture_output_frame_channels,
2361 &capture_output_frame);
2362
2363 for (size_t frame = 0; frame < 2; ++frame) {
2364 SCOPED_TRACE(ProduceDebugText(
2365 render_input_sample_rate_hz, render_output_sample_rate_hz,
2366 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2367 render_input_num_channels, render_output_num_channels,
2368 render_input_num_channels, capture_output_num_channels));
2369
2370 int result = apm->ProcessReverseStream(
2371 &render_input_frame[0], render_input_stream_config,
2372 render_output_stream_config, &render_output_frame[0]);
2373 EXPECT_EQ(result, AudioProcessing::kNoError);
2374 result = apm->ProcessStream(
2375 &capture_input_frame[0], capture_input_stream_config,
2376 capture_output_stream_config, &capture_output_frame[0]);
2377 EXPECT_EQ(result, AudioProcessing::kNoError);
2378 }
2379 }
2380 }
2381 }
2382 }
2383 }
2384 }
2385}
2386
Alessio Bazzica3438a932020-10-14 12:47:50 +02002387constexpr void Toggle(bool& b) {
2388 b ^= true;
2389}
2390
niklase@google.com470e71d2011-07-07 08:21:25 +00002391} // namespace
peahc19f3122016-10-07 14:54:10 -07002392
Alessio Bazzicac054e782018-04-16 12:10:09 +02002393TEST(RuntimeSettingTest, TestDefaultCtor) {
2394 auto s = AudioProcessing::RuntimeSetting();
2395 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2396}
2397
Alessio Bazzicac054e782018-04-16 12:10:09 +02002398TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2399 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2400 auto s = AudioProcessing::RuntimeSetting();
2401 ASSERT_TRUE(q.Insert(&s));
2402 ASSERT_TRUE(q.Remove(&s));
2403 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2404}
2405
Sam Zackrisson0beac582017-09-25 12:04:02 +02002406TEST(ApmConfiguration, EnablePostProcessing) {
2407 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 12:04:02 +02002408 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002409 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002410 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 16:02:40 +01002411 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002412 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002413 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002414 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002415 .Create();
Sam Zackrisson0beac582017-09-25 12:04:02 +02002416
Per Åhgren2507f8c2020-03-19 12:33:29 +01002417 Int16FrameData audio;
2418 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 12:04:02 +02002419 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2420
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002421 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002422 apm->ProcessStream(audio.data.data(),
2423 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2424 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002425 audio.data.data());
Sam Zackrisson0beac582017-09-25 12:04:02 +02002426}
2427
Alex Loiko5825aa62017-12-18 16:02:40 +01002428TEST(ApmConfiguration, EnablePreProcessing) {
2429 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 16:02:40 +01002430 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002431 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 16:02:40 +01002432 auto mock_pre_processor =
2433 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 14:17:33 +01002434 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002435 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 14:17:33 +01002436 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 10:52:28 +02002437 .Create();
Alex Loiko5825aa62017-12-18 16:02:40 +01002438
Per Åhgren2507f8c2020-03-19 12:33:29 +01002439 Int16FrameData audio;
2440 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 16:02:40 +01002441 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2442
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002443 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002444 apm->ProcessReverseStream(
2445 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2446 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2447 audio.data.data());
Alex Loiko5825aa62017-12-18 16:02:40 +01002448}
2449
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002450TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2451 // Verify that apm uses a capture analyzer if one is provided.
2452 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002453 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002454 auto mock_capture_analyzer =
2455 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2456 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002457 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002458 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2459 .Create();
2460
Per Åhgren2507f8c2020-03-19 12:33:29 +01002461 Int16FrameData audio;
2462 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002463 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2464
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002465 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002466 apm->ProcessStream(audio.data.data(),
2467 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2468 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002469 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 10:37:09 +02002470}
2471
Alex Loiko73ec0192018-05-15 10:52:28 +02002472TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2473 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002474 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 10:52:28 +02002475 auto mock_pre_processor =
2476 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2477 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002478 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 10:52:28 +02002479 .SetRenderPreProcessing(std::move(mock_pre_processor))
2480 .Create();
2481 apm->SetRuntimeSetting(
2482 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2483
2484 // RuntimeSettings forwarded during 'Process*Stream' calls.
2485 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002486 Int16FrameData audio;
2487 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 10:52:28 +02002488 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2489
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002490 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2491 .Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002492 apm->ProcessReverseStream(
2493 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2494 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2495 audio.data.data());
Alex Loiko73ec0192018-05-15 10:52:28 +02002496}
2497
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002498class MyEchoControlFactory : public EchoControlFactory {
2499 public:
2500 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2501 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 15:11:12 +02002502 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2503 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 11:12:29 +01002504 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2505 .Times(2);
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002506 return std::unique_ptr<EchoControl>(ec);
2507 }
Per Åhgrence202a02019-09-02 17:01:19 +02002508
2509 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 20:44:11 +01002510 int num_render_channels,
2511 int num_capture_channels) {
Per Åhgrence202a02019-09-02 17:01:19 +02002512 return Create(sample_rate_hz);
2513 }
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002514};
2515
2516TEST(ApmConfiguration, EchoControlInjection) {
2517 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002518 std::unique_ptr<EchoControlFactory> echo_control_factory(
2519 new MyEchoControlFactory());
2520
Alex Loiko5825aa62017-12-18 16:02:40 +01002521 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +02002522 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 11:35:59 +01002523 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 08:26:10 +02002524 .Create();
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002525
Per Åhgren2507f8c2020-03-19 12:33:29 +01002526 Int16FrameData audio;
2527 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002528 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
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());
Per Åhgren2507f8c2020-03-19 12:33:29 +01002533 apm->ProcessReverseStream(
2534 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2535 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2536 audio.data.data());
2537 apm->ProcessStream(audio.data.data(),
2538 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2539 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002540 audio.data.data());
Gustaf Ullberg002ef282017-10-12 15:13:17 +02002541}
Ivo Creusenae026092017-11-20 13:07:16 +01002542
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002543TEST(ApmConfiguration, EchoDetectorInjection) {
2544 using ::testing::_;
2545 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2546 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2547 EXPECT_CALL(*mock_echo_detector,
2548 Initialize(/*capture_sample_rate_hz=*/16000, _,
2549 /*render_sample_rate_hz=*/16000, _))
2550 .Times(1);
Niels Möller4f776ac2021-07-02 11:30:54 +02002551 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002552 AudioProcessingBuilderForTesting()
2553 .SetEchoDetector(mock_echo_detector)
2554 .Create();
2555
2556 // The echo detector is included in processing when enabled.
2557 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2558 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2559 EXPECT_EQ(render_audio.size(), 160u);
2560 });
2561 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2562 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2563 EXPECT_EQ(capture_audio.size(), 160u);
2564 });
2565 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2566
2567 Int16FrameData frame;
2568 frame.num_channels = 1;
2569 SetFrameSampleRate(&frame, 16000);
2570
2571 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2572 StreamConfig(16000, 1), frame.data.data());
2573 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2574 StreamConfig(16000, 1), frame.data.data());
2575
2576 // When processing rates change, the echo detector is also reinitialized to
2577 // match those.
2578 EXPECT_CALL(*mock_echo_detector,
2579 Initialize(/*capture_sample_rate_hz=*/48000, _,
2580 /*render_sample_rate_hz=*/16000, _))
2581 .Times(1);
2582 EXPECT_CALL(*mock_echo_detector,
2583 Initialize(/*capture_sample_rate_hz=*/48000, _,
2584 /*render_sample_rate_hz=*/48000, _))
2585 .Times(1);
2586 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2587 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2588 EXPECT_EQ(render_audio.size(), 480u);
2589 });
2590 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2591 .Times(2)
2592 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2593 EXPECT_EQ(capture_audio.size(), 480u);
2594 });
2595 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2596
2597 SetFrameSampleRate(&frame, 48000);
2598 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2599 StreamConfig(48000, 1), frame.data.data());
2600 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2601 StreamConfig(48000, 1), frame.data.data());
2602 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2603 StreamConfig(48000, 1), frame.data.data());
2604}
2605
2606rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2607 // Enable residual echo detection, for stats.
2608 rtc::scoped_refptr<AudioProcessing> apm =
2609 AudioProcessingBuilderForTesting()
2610 .SetEchoDetector(CreateEchoDetector())
2611 .Create();
Ivo Creusenae026092017-11-20 13:07:16 +01002612 if (!apm) {
2613 return apm;
2614 }
2615
2616 ProcessingConfig processing_config = {
2617 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2618
2619 if (apm->Initialize(processing_config) != 0) {
2620 return nullptr;
2621 }
2622
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002623 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002624 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002625 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;
Sam Zackrissoncdf0e6d2018-09-17 11:05:17 +02002631 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002632 return apm;
2633}
2634
2635#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2636#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2637#else
2638#define MAYBE_ApmStatistics ApmStatistics
2639#endif
2640
Per Åhgren8607f842019-04-12 22:02:26 +02002641TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2642 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002643 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae026092017-11-20 13:07:16 +01002644 ASSERT_TRUE(apm);
Per Åhgren200feba2019-03-06 04:16:46 +01002645 AudioProcessing::Config apm_config;
2646 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba2019-03-06 04:16:46 +01002647 apm->ApplyConfig(apm_config);
Ivo Creusenae026092017-11-20 13:07:16 +01002648
2649 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002650 Int16FrameData frame;
2651 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002652 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002653
2654 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002655 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002656 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2657 ptr[i] = 10000 * ((i % 3) - 1);
2658 }
2659
2660 // Do some processing.
2661 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002662 EXPECT_EQ(apm->ProcessReverseStream(
2663 frame.data.data(),
2664 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2665 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2666 frame.data.data()),
2667 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002668 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002669 EXPECT_EQ(apm->ProcessStream(
2670 frame.data.data(),
2671 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2672 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002673 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002674 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002675 }
2676
2677 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002678 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002679 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002680 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002681 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2682 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002683 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002684 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2685 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002686 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002687 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002688 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002689 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae026092017-11-20 13:07:16 +01002690}
2691
2692TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2693 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 11:30:54 +02002694 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae026092017-11-20 13:07:16 +01002695 ASSERT_TRUE(apm);
2696
2697 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002698 Int16FrameData frame;
2699 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002700 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae026092017-11-20 13:07:16 +01002701
2702 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002703 int16_t* ptr = frame.data.data();
Ivo Creusenae026092017-11-20 13:07:16 +01002704 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2705 ptr[i] = 10000 * ((i % 3) - 1);
2706 }
2707
2708 // Do some processing.
2709 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 12:33:29 +01002710 EXPECT_EQ(apm->ProcessReverseStream(
2711 frame.data.data(),
2712 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2713 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2714 frame.data.data()),
2715 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002716 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 12:33:29 +01002717 EXPECT_EQ(apm->ProcessStream(
2718 frame.data.data(),
2719 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2720 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002721 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002722 0);
Ivo Creusenae026092017-11-20 13:07:16 +01002723 }
2724
2725 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 14:32:14 +01002726 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae026092017-11-20 13:07:16 +01002727 // We expect only the residual echo detector statistics to be set and have a
2728 // sensible value.
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002729 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2730 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2731 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2732 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2733 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2734 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2735 EXPECT_FALSE(stats.echo_return_loss.has_value());
2736 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae026092017-11-20 13:07:16 +01002737}
Sam Zackrissonb24c00f2018-11-26 16:18:25 +01002738
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002739TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002740 ProcessingConfig processing_config = {
2741 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002742
2743 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002744 Int16FrameData frame;
2745 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002746 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2747
2748 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002749 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002750 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2751 ptr[i] = 10000 * ((i % 3) - 1);
2752 }
2753
Niels Möller4f776ac2021-07-02 11:30:54 +02002754 rtc::scoped_refptr<AudioProcessing> apm =
2755 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002756 apm->Initialize(processing_config);
2757
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002758 // No metric should be reported.
Per Åhgren2507f8c2020-03-19 12:33:29 +01002759 EXPECT_EQ(
2760 apm->ProcessStream(frame.data.data(),
2761 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2762 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 14:55:58 +01002763 frame.data.data()),
Per Åhgren2507f8c2020-03-19 12:33:29 +01002764 0);
Alessio Bazzica1db0a262022-02-15 14:18:09 +00002765 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
Sam Zackrisson4db667b2018-12-21 16:29:27 +01002766}
Per Åhgren3e8bf282019-08-29 23:38:40 +02002767
Sam Zackrisson03cb7e52021-12-06 15:40:04 +01002768TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2769 rtc::scoped_refptr<AudioProcessing> apm =
2770 AudioProcessingBuilderForTesting().Create();
2771 Int16FrameData frame;
2772 frame.num_channels = 1;
2773 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2774 ASSERT_EQ(
2775 apm->ProcessStream(frame.data.data(),
2776 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2777 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2778 frame.data.data()),
2779 0);
2780 // Echo detector is disabled by default, no stats reported.
2781 AudioProcessingStats stats = apm->GetStatistics();
2782 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2783 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2784}
2785
2786TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2787 // Create APM with an echo detector injected.
2788 rtc::scoped_refptr<AudioProcessing> apm =
2789 AudioProcessingBuilderForTesting()
2790 .SetEchoDetector(CreateEchoDetector())
2791 .Create();
2792 Int16FrameData frame;
2793 frame.num_channels = 1;
2794 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2795 // Echo detector enabled: Report stats.
2796 ASSERT_EQ(
2797 apm->ProcessStream(frame.data.data(),
2798 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2799 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2800 frame.data.data()),
2801 0);
2802 AudioProcessingStats stats = apm->GetStatistics();
2803 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2804 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2805}
2806
Per Åhgren3e8bf282019-08-29 23:38:40 +02002807TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2808 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2809 std::array<int, 2> render_channel_counts = {1, 7};
2810 std::array<int, 2> capture_channel_counts = {1, 7};
2811 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2812 capture_channel_counts);
2813}
2814
2815TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2816 std::array<int, 1> sample_rates_hz = {48000};
2817 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2818 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2819 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2820 capture_channel_counts);
2821}
2822
2823TEST(ApmConfiguration, HandlingOfRateCombinations) {
2824 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2825 48000, 96000, 192000, 384000};
2826 std::array<int, 1> render_channel_counts = {2};
2827 std::array<int, 1> capture_channel_counts = {2};
2828 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2829 capture_channel_counts);
2830}
2831
Yves Gerey1fce3f82019-12-05 17:45:31 +01002832TEST(ApmConfiguration, SelfAssignment) {
2833 // At some point memory sanitizer was complaining about self-assigment.
2834 // Make sure we don't regress.
2835 AudioProcessing::Config config;
2836 AudioProcessing::Config* config2 = &config;
2837 *config2 = *config2; // Workaround -Wself-assign-overloaded
2838 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2839}
2840
Alessio Bazzica3438a932020-10-14 12:47:50 +02002841TEST(AudioProcessing, GainController1ConfigEqual) {
2842 AudioProcessing::Config::GainController1 a;
2843 AudioProcessing::Config::GainController1 b;
2844 EXPECT_EQ(a, b);
2845
2846 Toggle(a.enabled);
2847 b.enabled = a.enabled;
2848 EXPECT_EQ(a, b);
2849
2850 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2851 b.mode = a.mode;
2852 EXPECT_EQ(a, b);
2853
2854 a.target_level_dbfs++;
2855 b.target_level_dbfs = a.target_level_dbfs;
2856 EXPECT_EQ(a, b);
2857
2858 a.compression_gain_db++;
2859 b.compression_gain_db = a.compression_gain_db;
2860 EXPECT_EQ(a, b);
2861
2862 Toggle(a.enable_limiter);
2863 b.enable_limiter = a.enable_limiter;
2864 EXPECT_EQ(a, b);
2865
Alessio Bazzica3438a932020-10-14 12:47:50 +02002866 auto& a_analog = a.analog_gain_controller;
2867 auto& b_analog = b.analog_gain_controller;
2868
2869 Toggle(a_analog.enabled);
2870 b_analog.enabled = a_analog.enabled;
2871 EXPECT_EQ(a, b);
2872
2873 a_analog.startup_min_volume++;
2874 b_analog.startup_min_volume = a_analog.startup_min_volume;
2875 EXPECT_EQ(a, b);
2876
2877 a_analog.clipped_level_min++;
2878 b_analog.clipped_level_min = a_analog.clipped_level_min;
2879 EXPECT_EQ(a, b);
2880
Alessio Bazzica3438a932020-10-14 12:47:50 +02002881 Toggle(a_analog.enable_digital_adaptive);
2882 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2883 EXPECT_EQ(a, b);
2884}
2885
2886// Checks that one differing parameter is sufficient to make two configs
2887// different.
2888TEST(AudioProcessing, GainController1ConfigNotEqual) {
2889 AudioProcessing::Config::GainController1 a;
2890 const AudioProcessing::Config::GainController1 b;
2891
2892 Toggle(a.enabled);
2893 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002894 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002895
2896 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2897 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002898 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002899
2900 a.target_level_dbfs++;
2901 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002902 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002903
2904 a.compression_gain_db++;
2905 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002906 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002907
2908 Toggle(a.enable_limiter);
2909 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002910 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002911
Alessio Bazzica3438a932020-10-14 12:47:50 +02002912 auto& a_analog = a.analog_gain_controller;
2913 const auto& b_analog = b.analog_gain_controller;
2914
2915 Toggle(a_analog.enabled);
2916 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002917 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002918
2919 a_analog.startup_min_volume++;
2920 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002921 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002922
2923 a_analog.clipped_level_min++;
2924 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002925 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002926
Alessio Bazzica3438a932020-10-14 12:47:50 +02002927 Toggle(a_analog.enable_digital_adaptive);
2928 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002929 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002930}
2931
2932TEST(AudioProcessing, GainController2ConfigEqual) {
2933 AudioProcessing::Config::GainController2 a;
2934 AudioProcessing::Config::GainController2 b;
2935 EXPECT_EQ(a, b);
2936
2937 Toggle(a.enabled);
2938 b.enabled = a.enabled;
2939 EXPECT_EQ(a, b);
2940
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002941 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002942 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
2943 EXPECT_EQ(a, b);
2944
2945 auto& a_adaptive = a.adaptive_digital;
2946 auto& b_adaptive = b.adaptive_digital;
2947
2948 Toggle(a_adaptive.enabled);
2949 b_adaptive.enabled = a_adaptive.enabled;
2950 EXPECT_EQ(a, b);
2951
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002952 Toggle(a_adaptive.dry_run);
2953 b_adaptive.dry_run = a_adaptive.dry_run;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002954 EXPECT_EQ(a, b);
2955
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02002956 a_adaptive.headroom_db += 1.0f;
2957 b_adaptive.headroom_db = a_adaptive.headroom_db;
2958 EXPECT_EQ(a, b);
2959
2960 a_adaptive.max_gain_db += 1.0f;
2961 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
2962 EXPECT_EQ(a, b);
2963
2964 a_adaptive.initial_gain_db += 1.0f;
2965 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
2966 EXPECT_EQ(a, b);
2967
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002968 a_adaptive.vad_reset_period_ms++;
2969 b_adaptive.vad_reset_period_ms = a_adaptive.vad_reset_period_ms;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002970 EXPECT_EQ(a, b);
2971
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002972 a_adaptive.adjacent_speech_frames_threshold++;
2973 b_adaptive.adjacent_speech_frames_threshold =
2974 a_adaptive.adjacent_speech_frames_threshold;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002975 EXPECT_EQ(a, b);
2976
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002977 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002978 b_adaptive.max_gain_change_db_per_second =
2979 a_adaptive.max_gain_change_db_per_second;
2980 EXPECT_EQ(a, b);
2981
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002982 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002983 b_adaptive.max_output_noise_level_dbfs =
2984 a_adaptive.max_output_noise_level_dbfs;
2985 EXPECT_EQ(a, b);
2986}
2987
2988// Checks that one differing parameter is sufficient to make two configs
2989// different.
2990TEST(AudioProcessing, GainController2ConfigNotEqual) {
2991 AudioProcessing::Config::GainController2 a;
2992 const AudioProcessing::Config::GainController2 b;
2993
2994 Toggle(a.enabled);
2995 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002996 a = b;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002997
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02002998 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02002999 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003000 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003001
3002 auto& a_adaptive = a.adaptive_digital;
3003 const auto& b_adaptive = b.adaptive_digital;
3004
3005 Toggle(a_adaptive.enabled);
3006 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003007 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003008
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003009 Toggle(a_adaptive.dry_run);
Alessio Bazzica3438a932020-10-14 12:47:50 +02003010 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003011 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003012
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +02003013 a_adaptive.headroom_db += 1.0f;
3014 EXPECT_NE(a, b);
3015 a_adaptive = b_adaptive;
3016
3017 a_adaptive.max_gain_db += 1.0f;
3018 EXPECT_NE(a, b);
3019 a_adaptive = b_adaptive;
3020
3021 a_adaptive.initial_gain_db += 1.0f;
3022 EXPECT_NE(a, b);
3023 a_adaptive = b_adaptive;
3024
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003025 a_adaptive.vad_reset_period_ms++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003026 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003027 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003028
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003029 a_adaptive.adjacent_speech_frames_threshold++;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003030 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003031 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003032
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003033 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003034 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003035 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003036
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003037 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003038 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 16:17:49 +02003039 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 12:47:50 +02003040}
3041
andrew@webrtc.org27c69802014-02-18 20:24:56 +00003042} // namespace webrtc