blob: 2d3684e9b53b8e6240164579323b13d063bc328e [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:251/*
andrew@webrtc.org293d22b2012-01-30 22:04:262 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:253 *
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 17:08:3310#include "modules/audio_processing/include/audio_processing.h"
11
andrew@webrtc.orgddbb8a22014-04-22 21:00:0412#include <math.h>
ajm@google.com59e41402011-07-28 17:34:0413#include <stdio.h>
kwiberg62eaacf2016-02-17 14:39:0514
andrew@webrtc.org07bf9a02012-05-05 00:32:0015#include <algorithm>
Oleh Prypin708eccc2019-03-27 08:38:5216#include <cmath>
andrew@webrtc.orgddbb8a22014-04-22 21:00:0417#include <limits>
kwiberg62eaacf2016-02-17 14:39:0518#include <memory>
Sam Zackrissone277bde2019-10-25 08:07:5419#include <numeric>
bjornv@webrtc.org3e102492013-02-14 15:29:0920#include <queue>
Ali Tofighf3592cb2022-08-16 12:44:3821#include <string>
andrew@webrtc.org07bf9a02012-05-05 00:32:0022
Sam Zackrisson6558fa52019-08-26 08:12:4123#include "absl/flags/flag.h"
Ali Tofighf3592cb2022-08-16 12:44:3824#include "absl/strings/string_view.h"
Sam Zackrisson03cb7e52021-12-06 14:40:0425#include "api/audio/echo_detector_creator.h"
Niels Möller105711e2022-06-14 13:48:2626#include "api/make_ref_counted.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3127#include "common_audio/include/audio_util.h"
28#include "common_audio/resampler/include/push_resampler.h"
29#include "common_audio/resampler/push_sinc_resampler.h"
30#include "common_audio/signal_processing/include/signal_processing_library.h"
31#include "modules/audio_processing/aec_dump/aec_dump_factory.h"
32#include "modules/audio_processing/audio_processing_impl.h"
Sam Zackrisson0beac582017-09-25 10:04:0233#include "modules/audio_processing/include/mock_audio_processing.h"
Per Åhgrencc73ed32020-04-26 21:56:1734#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3135#include "modules/audio_processing/test/protobuf_utils.h"
36#include "modules/audio_processing/test/test_utils.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3137#include "rtc_base/arraysize.h"
38#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 17:11:0039#include "rtc_base/fake_clock.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3140#include "rtc_base/gtest_prod_util.h"
Mirko Bonadei5b86f0a2017-11-29 14:20:2641#include "rtc_base/numerics/safe_conversions.h"
Karl Wiberge40468b2017-11-22 09:42:2642#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3143#include "rtc_base/protobuf_utils.h"
Jonas Olsson366a50c2018-09-06 11:41:3044#include "rtc_base/strings/string_builder.h"
Alessio Bazzicac054e782018-04-16 10:10:0945#include "rtc_base/swap_queue.h"
Niels Möllera12c42a2018-07-25 14:05:4846#include "rtc_base/system/arch.h"
Danil Chapovalov07122bc2019-03-26 13:37:0147#include "rtc_base/task_queue_for_test.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3148#include "rtc_base/thread.h"
Per Åhgrena43178c2020-09-25 10:02:3249#include "system_wrappers/include/cpu_features_wrapper.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3150#include "test/gtest.h"
Steve Anton10542f22019-01-11 17:11:0051#include "test/testsupport/file_utils.h"
kwiberg77eab702016-09-29 00:42:0152
leozwang@webrtc.orga3736342012-03-16 21:36:0053#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
Björn Tereliusefeeba02023-10-31 14:44:5054#include "external/webrtc/webrtc/modules/audio_processing/debug.pb.h"
leozwang@webrtc.org534e4952012-10-22 21:21:5255#include "external/webrtc/webrtc/modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:0056#else
Björn Tereliusefeeba02023-10-31 14:44:5057#include "modules/audio_processing/debug.pb.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3158#include "modules/audio_processing/test/unittest.pb.h"
leozwang@webrtc.orga3736342012-03-16 21:36:0059#endif
niklase@google.com470e71d2011-07-07 08:21:2560
Sam Zackrisson6558fa52019-08-26 08:12:4161ABSL_FLAG(bool,
62 write_apm_ref_data,
63 false,
64 "Write ApmTest.Process results to file, instead of comparing results "
65 "to the existing reference data file.");
66
andrew@webrtc.org27c69802014-02-18 20:24:5667namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:2568namespace {
andrew@webrtc.org17e40642014-03-04 20:58:1369
Sam Zackrisson3bd444f2022-08-03 12:37:0070// All sample rates used by APM internally during processing. Other input /
71// output rates are resampled to / from one of these.
72const int kProcessSampleRates[] = {16000, 32000, 48000};
andrew@webrtc.org07bf9a02012-05-05 00:32:0073
ekmeyerson60d9b332015-08-14 17:35:5574enum StreamDirection { kForward = 0, kReverse };
75
andrew@webrtc.orgddbb8a22014-04-22 21:00:0476void ConvertToFloat(const int16_t* int_data, ChannelBuffer<float>* cb) {
Jonas Olssona4d87372019-07-05 17:08:3377 ChannelBuffer<int16_t> cb_int(cb->num_frames(), cb->num_channels());
78 Deinterleave(int_data, cb->num_frames(), cb->num_channels(),
andrew@webrtc.orga8b97372014-03-10 22:26:1279 cb_int.channels());
Peter Kasting69558702016-01-13 00:26:3580 for (size_t i = 0; i < cb->num_channels(); ++i) {
Jonas Olssona4d87372019-07-05 17:08:3381 S16ToFloat(cb_int.channels()[i], cb->num_frames(), cb->channels()[i]);
aluebs@webrtc.orgd35a5c32015-02-10 22:52:1582 }
andrew@webrtc.orga8b97372014-03-10 22:26:1283}
andrew@webrtc.org17e40642014-03-04 20:58:1384
Per Åhgren2507f8c2020-03-19 11:33:2985void ConvertToFloat(const Int16FrameData& frame, ChannelBuffer<float>* cb) {
86 ConvertToFloat(frame.data.data(), cb);
andrew@webrtc.orgddbb8a22014-04-22 21:00:0487}
88
Jonas Olssona4d87372019-07-05 17:08:3389void MixStereoToMono(const float* stereo,
90 float* mono,
pkasting25702cb2016-01-08 21:50:2791 size_t samples_per_channel) {
92 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:0493 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) / 2;
andrew@webrtc.org81865342012-10-27 00:28:2794}
95
Jonas Olssona4d87372019-07-05 17:08:3396void MixStereoToMono(const int16_t* stereo,
97 int16_t* mono,
pkasting25702cb2016-01-08 21:50:2798 size_t samples_per_channel) {
99 for (size_t i = 0; i < samples_per_channel; ++i)
andrew@webrtc.orgddbb8a22014-04-22 21:00:04100 mono[i] = (stereo[i * 2] + stereo[i * 2 + 1]) >> 1;
101}
102
pkasting25702cb2016-01-08 21:50:27103void CopyLeftToRightChannel(int16_t* stereo, size_t samples_per_channel) {
104 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27105 stereo[i * 2 + 1] = stereo[i * 2];
106 }
107}
108
yujo36b1a5f2017-06-12 19:45:32109void VerifyChannelsAreEqual(const int16_t* stereo, size_t samples_per_channel) {
pkasting25702cb2016-01-08 21:50:27110 for (size_t i = 0; i < samples_per_channel; i++) {
andrew@webrtc.org81865342012-10-27 00:28:27111 EXPECT_EQ(stereo[i * 2 + 1], stereo[i * 2]);
112 }
113}
114
Per Åhgren2507f8c2020-03-19 11:33:29115void SetFrameTo(Int16FrameData* frame, int16_t value) {
116 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 21:52:23117 ++i) {
Per Åhgren2507f8c2020-03-19 11:33:29118 frame->data[i] = value;
andrew@webrtc.org81865342012-10-27 00:28:27119 }
120}
121
Per Åhgren2507f8c2020-03-19 11:33:29122void SetFrameTo(Int16FrameData* frame, int16_t left, int16_t right) {
123 ASSERT_EQ(2u, frame->num_channels);
124 for (size_t i = 0; i < frame->samples_per_channel * 2; i += 2) {
125 frame->data[i] = left;
126 frame->data[i + 1] = right;
andrew@webrtc.org81865342012-10-27 00:28:27127 }
128}
129
Per Åhgren2507f8c2020-03-19 11:33:29130void ScaleFrame(Int16FrameData* frame, float scale) {
131 for (size_t i = 0; i < frame->samples_per_channel * frame->num_channels;
Peter Kastingdce40cf2015-08-24 21:52:23132 ++i) {
Per Åhgren2507f8c2020-03-19 11:33:29133 frame->data[i] = FloatS16ToS16(frame->data[i] * scale);
andrew@webrtc.org27c69802014-02-18 20:24:56134 }
135}
136
Per Åhgren2507f8c2020-03-19 11:33:29137bool FrameDataAreEqual(const Int16FrameData& frame1,
138 const Int16FrameData& frame2) {
139 if (frame1.samples_per_channel != frame2.samples_per_channel) {
andrew@webrtc.org81865342012-10-27 00:28:27140 return false;
141 }
Per Åhgren2507f8c2020-03-19 11:33:29142 if (frame1.num_channels != frame2.num_channels) {
andrew@webrtc.org81865342012-10-27 00:28:27143 return false;
144 }
Per Åhgren2507f8c2020-03-19 11:33:29145 if (memcmp(
146 frame1.data.data(), frame2.data.data(),
147 frame1.samples_per_channel * frame1.num_channels * sizeof(int16_t))) {
andrew@webrtc.org81865342012-10-27 00:28:27148 return false;
149 }
150 return true;
151}
152
Per Åhgren2507f8c2020-03-19 11:33:29153rtc::ArrayView<int16_t> GetMutableFrameData(Int16FrameData* frame) {
154 int16_t* ptr = frame->data.data();
155 const size_t len = frame->samples_per_channel * frame->num_channels;
Sam Zackrissone277bde2019-10-25 08:07:54156 return rtc::ArrayView<int16_t>(ptr, len);
157}
158
Per Åhgren2507f8c2020-03-19 11:33:29159rtc::ArrayView<const int16_t> GetFrameData(const Int16FrameData& frame) {
160 const int16_t* ptr = frame.data.data();
161 const size_t len = frame.samples_per_channel * frame.num_channels;
Sam Zackrissone277bde2019-10-25 08:07:54162 return rtc::ArrayView<const int16_t>(ptr, len);
163}
164
andrew@webrtc.org17e40642014-03-04 20:58:13165void EnableAllAPComponents(AudioProcessing* ap) {
Sam Zackrissonb3b47ad2018-08-17 14:26:14166 AudioProcessing::Config apm_config = ap->GetConfig();
167 apm_config.echo_canceller.enabled = true;
andrew@webrtc.org17e40642014-03-04 20:58:13168#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 14:26:14169 apm_config.echo_canceller.mobile_mode = true;
Sam Zackrissonf0d1c032019-03-27 12:28:08170
171 apm_config.gain_controller1.enabled = true;
172 apm_config.gain_controller1.mode =
173 AudioProcessing::Config::GainController1::kAdaptiveDigital;
andrew@webrtc.org17e40642014-03-04 20:58:13174#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Sam Zackrissonb3b47ad2018-08-17 14:26:14175 apm_config.echo_canceller.mobile_mode = false;
andrew@webrtc.org17e40642014-03-04 20:58:13176
Sam Zackrissonf0d1c032019-03-27 12:28:08177 apm_config.gain_controller1.enabled = true;
178 apm_config.gain_controller1.mode =
179 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
andrew@webrtc.org17e40642014-03-04 20:58:13180#endif
Sam Zackrisson2a959d92018-07-23 14:48:07181
saza0bad15f2019-10-16 09:46:11182 apm_config.noise_suppression.enabled = true;
183
peah8271d042016-11-22 15:24:52184 apm_config.high_pass_filter.enabled = true;
Per Åhgrenc0424252019-12-10 12:04:15185 apm_config.pipeline.maximum_internal_processing_rate = 48000;
peah8271d042016-11-22 15:24:52186 ap->ApplyConfig(apm_config);
andrew@webrtc.org17e40642014-03-04 20:58:13187}
188
bjornv@webrtc.org8dd60cc2014-09-11 08:36:35189// These functions are only used by ApmTest.Process.
andrew@webrtc.orgd7696c42013-12-03 23:39:16190template <class T>
191T AbsValue(T a) {
Jonas Olssona4d87372019-07-05 17:08:33192 return a > 0 ? a : -a;
andrew@webrtc.orgd7696c42013-12-03 23:39:16193}
194
Per Åhgren2507f8c2020-03-19 11:33:29195int16_t MaxAudioFrame(const Int16FrameData& frame) {
196 const size_t length = frame.samples_per_channel * frame.num_channels;
197 int16_t max_data = AbsValue(frame.data[0]);
pkasting25702cb2016-01-08 21:50:27198 for (size_t i = 1; i < length; i++) {
Per Åhgren2507f8c2020-03-19 11:33:29199 max_data = std::max(max_data, AbsValue(frame.data[i]));
andrew@webrtc.orgd7696c42013-12-03 23:39:16200 }
201
202 return max_data;
203}
204
Ali Tofighf3592cb2022-08-16 12:44:38205void OpenFileAndWriteMessage(absl::string_view filename,
mbonadei7c2c8432017-04-07 07:59:12206 const MessageLite& msg) {
Ali Tofighf3592cb2022-08-16 12:44:38207 FILE* file = fopen(std::string(filename).c_str(), "wb");
andrew@webrtc.orga8b97372014-03-10 22:26:12208 ASSERT_TRUE(file != NULL);
209
Mirko Bonadei5b86f0a2017-11-29 14:20:26210 int32_t size = rtc::checked_cast<int32_t>(msg.ByteSizeLong());
andrew@webrtc.org81865342012-10-27 00:28:27211 ASSERT_GT(size, 0);
kwiberg62eaacf2016-02-17 14:39:05212 std::unique_ptr<uint8_t[]> array(new uint8_t[size]);
andrew@webrtc.orga8b97372014-03-10 22:26:12213 ASSERT_TRUE(msg.SerializeToArray(array.get(), size));
andrew@webrtc.org81865342012-10-27 00:28:27214
andrew@webrtc.orga8b97372014-03-10 22:26:12215 ASSERT_EQ(1u, fwrite(&size, sizeof(size), 1, file));
andrew@webrtc.org81865342012-10-27 00:28:27216 ASSERT_EQ(static_cast<size_t>(size),
Jonas Olssona4d87372019-07-05 17:08:33217 fwrite(array.get(), sizeof(array[0]), size, file));
andrew@webrtc.org81865342012-10-27 00:28:27218 fclose(file);
219}
220
Ali Tofighf3592cb2022-08-16 12:44:38221std::string ResourceFilePath(absl::string_view name, int sample_rate_hz) {
Jonas Olsson366a50c2018-09-06 11:41:30222 rtc::StringBuilder ss;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04223 // Resource files are all stereo.
224 ss << name << sample_rate_hz / 1000 << "_stereo";
225 return test::ResourcePath(ss.str(), "pcm");
226}
227
pbos@webrtc.orga525c982015-01-12 17:31:18228// Temporary filenames unique to this process. Used to be able to run these
229// tests in parallel as each process needs to be running in isolation they can't
230// have competing filenames.
231std::map<std::string, std::string> temp_filenames;
232
Ali Tofighf3592cb2022-08-16 12:44:38233std::string OutputFilePath(absl::string_view name,
andrew@webrtc.orgf26c9e82014-04-24 03:46:46234 int input_rate,
235 int output_rate,
ekmeyerson60d9b332015-08-14 17:35:55236 int reverse_input_rate,
237 int reverse_output_rate,
Peter Kasting69558702016-01-13 00:26:35238 size_t num_input_channels,
239 size_t num_output_channels,
240 size_t num_reverse_input_channels,
241 size_t num_reverse_output_channels,
ekmeyerson60d9b332015-08-14 17:35:55242 StreamDirection file_direction) {
Jonas Olsson366a50c2018-09-06 11:41:30243 rtc::StringBuilder ss;
ekmeyerson60d9b332015-08-14 17:35:55244 ss << name << "_i" << num_input_channels << "_" << input_rate / 1000 << "_ir"
245 << num_reverse_input_channels << "_" << reverse_input_rate / 1000 << "_";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04246 if (num_output_channels == 1) {
247 ss << "mono";
248 } else if (num_output_channels == 2) {
249 ss << "stereo";
250 } else {
Artem Titovd3251962021-11-15 15:57:07251 RTC_DCHECK_NOTREACHED();
andrew@webrtc.orgddbb8a22014-04-22 21:00:04252 }
ekmeyerson60d9b332015-08-14 17:35:55253 ss << output_rate / 1000;
254 if (num_reverse_output_channels == 1) {
255 ss << "_rmono";
256 } else if (num_reverse_output_channels == 2) {
257 ss << "_rstereo";
258 } else {
Artem Titovd3251962021-11-15 15:57:07259 RTC_DCHECK_NOTREACHED();
ekmeyerson60d9b332015-08-14 17:35:55260 }
261 ss << reverse_output_rate / 1000;
262 ss << "_d" << file_direction << "_pcm";
andrew@webrtc.orgddbb8a22014-04-22 21:00:04263
pbos@webrtc.orga525c982015-01-12 17:31:18264 std::string filename = ss.str();
pbosbb36fdf2015-07-09 14:48:14265 if (temp_filenames[filename].empty())
pbos@webrtc.orga525c982015-01-12 17:31:18266 temp_filenames[filename] = test::TempFilename(test::OutputPath(), filename);
267 return temp_filenames[filename];
andrew@webrtc.orgddbb8a22014-04-22 21:00:04268}
269
pbos@webrtc.org200ac002015-02-03 14:14:01270void ClearTempFiles() {
271 for (auto& kv : temp_filenames)
272 remove(kv.second.c_str());
273}
274
Gustaf Ullberg8ffeeb22017-10-11 09:42:38275// Only remove "out" files. Keep "ref" files.
276void ClearTempOutFiles() {
277 for (auto it = temp_filenames.begin(); it != temp_filenames.end();) {
278 const std::string& filename = it->first;
279 if (filename.substr(0, 3).compare("out") == 0) {
280 remove(it->second.c_str());
281 temp_filenames.erase(it++);
282 } else {
283 it++;
284 }
285 }
286}
287
Ali Tofighf3592cb2022-08-16 12:44:38288void OpenFileAndReadMessage(absl::string_view filename, MessageLite* msg) {
289 FILE* file = fopen(std::string(filename).c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:12290 ASSERT_TRUE(file != NULL);
291 ReadMessageFromFile(file, msg);
andrew@webrtc.org81865342012-10-27 00:28:27292 fclose(file);
293}
294
Sam Zackrisson3bd444f2022-08-03 12:37:00295// Reads a 10 ms chunk (actually AudioProcessing::GetFrameSize() samples per
296// channel) of int16 interleaved audio from the given (assumed stereo) file,
297// converts to deinterleaved float (optionally downmixing) and returns the
298// result in `cb`. Returns false if the file ended (or on error) and true
299// otherwise.
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21300//
Artem Titov0b489302021-07-28 18:50:03301// `int_data` and `float_data` are just temporary space that must be
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21302// sufficiently large to hold the 10 ms chunk.
Jonas Olssona4d87372019-07-05 17:08:33303bool ReadChunk(FILE* file,
304 int16_t* int_data,
305 float* float_data,
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21306 ChannelBuffer<float>* cb) {
307 // The files always contain stereo audio.
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15308 size_t frame_size = cb->num_frames() * 2;
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21309 size_t read_count = fread(int_data, sizeof(int16_t), frame_size, file);
310 if (read_count != frame_size) {
311 // Check that the file really ended.
kwiberg9e2be5f2016-09-14 12:23:22312 RTC_DCHECK(feof(file));
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21313 return false; // This is expected.
314 }
315
316 S16ToFloat(int_data, frame_size, float_data);
317 if (cb->num_channels() == 1) {
aluebs@webrtc.orgd35a5c32015-02-10 22:52:15318 MixStereoToMono(float_data, cb->channels()[0], cb->num_frames());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21319 } else {
Jonas Olssona4d87372019-07-05 17:08:33320 Deinterleave(float_data, cb->num_frames(), 2, cb->channels());
aluebs@webrtc.orgd82f55d2015-01-15 18:07:21321 }
322
323 return true;
324}
325
Per Åhgrena43178c2020-09-25 10:02:32326// Returns the reference file name that matches the current CPU
327// architecture/optimizations.
328std::string GetReferenceFilename() {
329#if defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
330 return test::ResourcePath("audio_processing/output_data_fixed", "pb");
331#elif defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
332 if (GetCPUInfo(kAVX2) != 0) {
333 return test::ResourcePath("audio_processing/output_data_float_avx2", "pb");
334 }
335 return test::ResourcePath("audio_processing/output_data_float", "pb");
336#endif
337}
338
Alessio Bazzica85a126e2022-08-11 13:48:54339// Flag that can temporarily be enabled for local debugging to inspect
340// `ApmTest.VerifyDebugDump(Int|Float)` failures. Do not upload code changes
341// with this flag set to true.
342constexpr bool kDumpWhenExpectMessageEqFails = false;
343
344// Checks the debug constants values used in this file so that no code change is
345// submitted with values temporarily used for local debugging.
346TEST(ApmUnitTests, CheckDebugConstants) {
347 ASSERT_FALSE(kDumpWhenExpectMessageEqFails);
348}
349
350// Expects the equality of `actual` and `expected` by inspecting a hard-coded
351// subset of `audioproc::Stream` fields.
352void ExpectStreamFieldsEq(const audioproc::Stream& actual,
353 const audioproc::Stream& expected) {
354 EXPECT_EQ(actual.input_data(), expected.input_data());
355 EXPECT_EQ(actual.output_data(), expected.output_data());
356 EXPECT_EQ(actual.delay(), expected.delay());
357 EXPECT_EQ(actual.drift(), expected.drift());
Alessio Bazzica3153b362022-09-05 14:05:24358 EXPECT_EQ(actual.applied_input_volume(), expected.applied_input_volume());
Alessio Bazzica85a126e2022-08-11 13:48:54359 EXPECT_EQ(actual.keypress(), expected.keypress());
360}
361
362// Expects the equality of `actual` and `expected` by inspecting a hard-coded
363// subset of `audioproc::Event` fields.
364void ExpectEventFieldsEq(const audioproc::Event& actual,
365 const audioproc::Event& expected) {
366 EXPECT_EQ(actual.type(), expected.type());
367 if (actual.type() != expected.type()) {
368 return;
369 }
370 switch (actual.type()) {
371 case audioproc::Event::STREAM:
372 ExpectStreamFieldsEq(actual.stream(), expected.stream());
373 break;
374 default:
375 // Not implemented.
376 break;
377 }
378}
379
380// Returns true if the `actual` and `expected` byte streams share the same size
381// and contain the same data. If they differ and `kDumpWhenExpectMessageEqFails`
382// is true, checks the equality of a subset of `audioproc::Event` (nested)
383// fields.
384bool ExpectMessageEq(rtc::ArrayView<const uint8_t> actual,
385 rtc::ArrayView<const uint8_t> expected) {
386 EXPECT_EQ(actual.size(), expected.size());
387 if (actual.size() != expected.size()) {
388 return false;
389 }
390 if (memcmp(actual.data(), expected.data(), actual.size()) == 0) {
391 // Same message. No need to parse.
392 return true;
393 }
394 if (kDumpWhenExpectMessageEqFails) {
395 // Parse differing messages and expect equality to produce detailed error
396 // messages.
397 audioproc::Event event_actual, event_expected;
398 RTC_DCHECK(event_actual.ParseFromArray(actual.data(), actual.size()));
399 RTC_DCHECK(event_expected.ParseFromArray(expected.data(), expected.size()));
400 ExpectEventFieldsEq(event_actual, event_expected);
401 }
402 return false;
403}
404
niklase@google.com470e71d2011-07-07 08:21:25405class ApmTest : public ::testing::Test {
406 protected:
407 ApmTest();
408 virtual void SetUp();
409 virtual void TearDown();
andrew@webrtc.org755b04a2011-11-15 16:57:56410
Mirko Bonadei71061bc2019-06-04 07:01:51411 static void SetUpTestSuite() {}
andrew@webrtc.org755b04a2011-11-15 16:57:56412
Mirko Bonadei71061bc2019-06-04 07:01:51413 static void TearDownTestSuite() { ClearTempFiles(); }
andrew@webrtc.orgdaacee82012-02-07 00:01:04414
andrew@webrtc.orga8b97372014-03-10 22:26:12415 // Used to select between int and float interface tests.
Jonas Olssona4d87372019-07-05 17:08:33416 enum Format { kIntFormat, kFloatFormat };
andrew@webrtc.orga8b97372014-03-10 22:26:12417
418 void Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04419 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12420 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-13 00:26:35421 size_t num_input_channels,
422 size_t num_output_channels,
423 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04424 bool open_output_file);
andrew@webrtc.org17e40642014-03-04 20:58:13425 void Init(AudioProcessing* ap);
andrew@webrtc.org07bf9a02012-05-05 00:32:00426 void EnableAllComponents();
Per Åhgren2507f8c2020-03-19 11:33:29427 bool ReadFrame(FILE* file, Int16FrameData* frame);
428 bool ReadFrame(FILE* file, Int16FrameData* frame, ChannelBuffer<float>* cb);
429 void ReadFrameWithRewind(FILE* file, Int16FrameData* frame);
Jonas Olssona4d87372019-07-05 17:08:33430 void ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 11:33:29431 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13432 ChannelBuffer<float>* cb);
Jonas Olssona4d87372019-07-05 17:08:33433 void ProcessDelayVerificationTest(int delay_ms,
434 int system_delay_ms,
435 int delay_min,
436 int delay_max);
Michael Graczyk86c6d332015-07-23 18:41:39437 void TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-13 00:26:35438 size_t num_channels,
Michael Graczyk86c6d332015-07-23 18:41:39439 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-13 00:26:35440 void TestChangingForwardChannels(size_t num_in_channels,
441 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 18:41:39442 AudioProcessing::Error expected_return);
Peter Kasting69558702016-01-13 00:26:35443 void TestChangingReverseChannels(size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 18:41:39444 AudioProcessing::Error expected_return);
andrew@webrtc.org27c69802014-02-18 20:24:56445 void RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate);
446 void RunManualVolumeChangeIsPossibleTest(int sample_rate);
andrew@webrtc.orga8b97372014-03-10 22:26:12447 void StreamParametersTest(Format format);
andrew@webrtc.orga8b97372014-03-10 22:26:12448 int ProcessStreamChooser(Format format);
449 int AnalyzeReverseStreamChooser(Format format);
Ali Tofighf3592cb2022-08-16 12:44:38450 void ProcessDebugDump(absl::string_view in_filename,
451 absl::string_view out_filename,
ivocd66b44d2016-01-15 11:06:36452 Format format,
453 int max_size_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:12454 void VerifyDebugDumpTest(Format format);
andrew@webrtc.orgdaacee82012-02-07 00:01:04455
456 const std::string output_path_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04457 const std::string ref_filename_;
Niels Möller4f776ac2021-07-02 09:30:54458 rtc::scoped_refptr<AudioProcessing> apm_;
Per Åhgren2507f8c2020-03-19 11:33:29459 Int16FrameData frame_;
460 Int16FrameData revframe_;
Sam Zackrisson03cb7e52021-12-06 14:40:04461 std::unique_ptr<ChannelBuffer<float>> float_cb_;
462 std::unique_ptr<ChannelBuffer<float>> revfloat_cb_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:04463 int output_sample_rate_hz_;
Peter Kasting69558702016-01-13 00:26:35464 size_t num_output_channels_;
niklase@google.com470e71d2011-07-07 08:21:25465 FILE* far_file_;
466 FILE* near_file_;
andrew@webrtc.orgdaacee82012-02-07 00:01:04467 FILE* out_file_;
niklase@google.com470e71d2011-07-07 08:21:25468};
469
470ApmTest::ApmTest()
andrew@webrtc.org27c69802014-02-18 20:24:56471 : output_path_(test::OutputPath()),
Per Åhgrena43178c2020-09-25 10:02:32472 ref_filename_(GetReferenceFilename()),
andrew@webrtc.orgddbb8a22014-04-22 21:00:04473 output_sample_rate_hz_(0),
andrew@webrtc.orga8b97372014-03-10 22:26:12474 num_output_channels_(0),
ajm@google.com22e65152011-07-18 18:03:01475 far_file_(NULL),
andrew@webrtc.orgdaacee82012-02-07 00:01:04476 near_file_(NULL),
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57477 out_file_(NULL) {
Niels Möller4f776ac2021-07-02 09:30:54478 apm_ = AudioProcessingBuilderForTesting().Create();
Per Åhgrenc0424252019-12-10 12:04:15479 AudioProcessing::Config apm_config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:13480 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Per Åhgrenc0424252019-12-10 12:04:15481 apm_config.pipeline.maximum_internal_processing_rate = 48000;
482 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgc9ee4122014-02-03 14:41:57483}
niklase@google.com470e71d2011-07-07 08:21:25484
485void ApmTest::SetUp() {
andrew@webrtc.orgf3930e92013-09-18 22:37:32486 ASSERT_TRUE(apm_.get() != NULL);
niklase@google.com470e71d2011-07-07 08:21:25487
andrew@webrtc.orgddbb8a22014-04-22 21:00:04488 Init(32000, 32000, 32000, 2, 2, 2, false);
niklase@google.com470e71d2011-07-07 08:21:25489}
490
491void ApmTest::TearDown() {
niklase@google.com470e71d2011-07-07 08:21:25492 if (far_file_) {
493 ASSERT_EQ(0, fclose(far_file_));
494 }
495 far_file_ = NULL;
496
497 if (near_file_) {
498 ASSERT_EQ(0, fclose(near_file_));
499 }
500 near_file_ = NULL;
501
andrew@webrtc.orgdaacee82012-02-07 00:01:04502 if (out_file_) {
503 ASSERT_EQ(0, fclose(out_file_));
504 }
505 out_file_ = NULL;
niklase@google.com470e71d2011-07-07 08:21:25506}
507
andrew@webrtc.org17e40642014-03-04 20:58:13508void ApmTest::Init(AudioProcessing* ap) {
Sam Zackrisson70770ac2019-10-25 08:56:53509 ASSERT_EQ(
510 kNoErr,
Per Åhgren2507f8c2020-03-19 11:33:29511 ap->Initialize({{{frame_.sample_rate_hz, frame_.num_channels},
Sam Zackrisson70770ac2019-10-25 08:56:53512 {output_sample_rate_hz_, num_output_channels_},
Per Åhgren2507f8c2020-03-19 11:33:29513 {revframe_.sample_rate_hz, revframe_.num_channels},
514 {revframe_.sample_rate_hz, revframe_.num_channels}}}));
andrew@webrtc.org17e40642014-03-04 20:58:13515}
516
andrew@webrtc.orga8b97372014-03-10 22:26:12517void ApmTest::Init(int sample_rate_hz,
andrew@webrtc.orgddbb8a22014-04-22 21:00:04518 int output_sample_rate_hz,
andrew@webrtc.orga8b97372014-03-10 22:26:12519 int reverse_sample_rate_hz,
Peter Kasting69558702016-01-13 00:26:35520 size_t num_input_channels,
521 size_t num_output_channels,
522 size_t num_reverse_channels,
andrew@webrtc.orgdaacee82012-02-07 00:01:04523 bool open_output_file) {
Sam Zackrisson70770ac2019-10-25 08:56:53524 SetContainerFormat(sample_rate_hz, num_input_channels, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04525 output_sample_rate_hz_ = output_sample_rate_hz;
andrew@webrtc.orga8b97372014-03-10 22:26:12526 num_output_channels_ = num_output_channels;
andrew@webrtc.orgdaacee82012-02-07 00:01:04527
Sam Zackrisson70770ac2019-10-25 08:56:53528 SetContainerFormat(reverse_sample_rate_hz, num_reverse_channels, &revframe_,
andrew@webrtc.orga8b97372014-03-10 22:26:12529 &revfloat_cb_);
andrew@webrtc.org17e40642014-03-04 20:58:13530 Init(apm_.get());
andrew@webrtc.org60730cf2014-01-07 17:45:09531
andrew@webrtc.orgdaacee82012-02-07 00:01:04532 if (far_file_) {
533 ASSERT_EQ(0, fclose(far_file_));
534 }
535 std::string filename = ResourceFilePath("far", sample_rate_hz);
536 far_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 17:08:33537 ASSERT_TRUE(far_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04538
539 if (near_file_) {
540 ASSERT_EQ(0, fclose(near_file_));
541 }
542 filename = ResourceFilePath("near", sample_rate_hz);
543 near_file_ = fopen(filename.c_str(), "rb");
Jonas Olssona4d87372019-07-05 17:08:33544 ASSERT_TRUE(near_file_ != NULL) << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04545
546 if (open_output_file) {
547 if (out_file_) {
548 ASSERT_EQ(0, fclose(out_file_));
549 }
ekmeyerson60d9b332015-08-14 17:35:55550 filename = OutputFilePath(
551 "out", sample_rate_hz, output_sample_rate_hz, reverse_sample_rate_hz,
552 reverse_sample_rate_hz, num_input_channels, num_output_channels,
553 num_reverse_channels, num_reverse_channels, kForward);
andrew@webrtc.orgdaacee82012-02-07 00:01:04554 out_file_ = fopen(filename.c_str(), "wb");
Jonas Olssona4d87372019-07-05 17:08:33555 ASSERT_TRUE(out_file_ != NULL)
556 << "Could not open file " << filename << "\n";
andrew@webrtc.orgdaacee82012-02-07 00:01:04557 }
558}
559
andrew@webrtc.org07bf9a02012-05-05 00:32:00560void ApmTest::EnableAllComponents() {
andrew@webrtc.org17e40642014-03-04 20:58:13561 EnableAllAPComponents(apm_.get());
andrew@webrtc.org07bf9a02012-05-05 00:32:00562}
563
Jonas Olssona4d87372019-07-05 17:08:33564bool ApmTest::ReadFrame(FILE* file,
Per Åhgren2507f8c2020-03-19 11:33:29565 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13566 ChannelBuffer<float>* cb) {
andrew@webrtc.org07bf9a02012-05-05 00:32:00567 // The files always contain stereo audio.
Per Åhgren2507f8c2020-03-19 11:33:29568 size_t frame_size = frame->samples_per_channel * 2;
Jonas Olssona4d87372019-07-05 17:08:33569 size_t read_count =
Per Åhgren2507f8c2020-03-19 11:33:29570 fread(frame->data.data(), sizeof(int16_t), frame_size, file);
andrew@webrtc.org07bf9a02012-05-05 00:32:00571 if (read_count != frame_size) {
572 // Check that the file really ended.
573 EXPECT_NE(0, feof(file));
574 return false; // This is expected.
575 }
576
Per Åhgren2507f8c2020-03-19 11:33:29577 if (frame->num_channels == 1) {
578 MixStereoToMono(frame->data.data(), frame->data.data(),
579 frame->samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:00580 }
581
andrew@webrtc.org17e40642014-03-04 20:58:13582 if (cb) {
andrew@webrtc.orga8b97372014-03-10 22:26:12583 ConvertToFloat(*frame, cb);
andrew@webrtc.org17e40642014-03-04 20:58:13584 }
andrew@webrtc.org07bf9a02012-05-05 00:32:00585 return true;
ajm@google.coma769fa52011-07-13 21:57:58586}
587
Per Åhgren2507f8c2020-03-19 11:33:29588bool ApmTest::ReadFrame(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13589 return ReadFrame(file, frame, NULL);
590}
591
andrew@webrtc.org27c69802014-02-18 20:24:56592// If the end of the file has been reached, rewind it and attempt to read the
593// frame again.
Jonas Olssona4d87372019-07-05 17:08:33594void ApmTest::ReadFrameWithRewind(FILE* file,
Per Åhgren2507f8c2020-03-19 11:33:29595 Int16FrameData* frame,
andrew@webrtc.org17e40642014-03-04 20:58:13596 ChannelBuffer<float>* cb) {
Sam Zackrisson70770ac2019-10-25 08:56:53597 if (!ReadFrame(near_file_, &frame_, cb)) {
andrew@webrtc.org27c69802014-02-18 20:24:56598 rewind(near_file_);
Sam Zackrisson70770ac2019-10-25 08:56:53599 ASSERT_TRUE(ReadFrame(near_file_, &frame_, cb));
andrew@webrtc.org27c69802014-02-18 20:24:56600 }
601}
602
Per Åhgren2507f8c2020-03-19 11:33:29603void ApmTest::ReadFrameWithRewind(FILE* file, Int16FrameData* frame) {
andrew@webrtc.org17e40642014-03-04 20:58:13604 ReadFrameWithRewind(file, frame, NULL);
605}
606
andrew@webrtc.orga8b97372014-03-10 22:26:12607int ApmTest::ProcessStreamChooser(Format format) {
608 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 11:33:29609 return apm_->ProcessStream(
610 frame_.data.data(),
611 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
612 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:58613 frame_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13614 }
Jonas Olssona4d87372019-07-05 17:08:33615 return apm_->ProcessStream(
Gustaf Ullbergcb307262019-10-29 08:30:44616 float_cb_->channels(),
Per Åhgren2507f8c2020-03-19 11:33:29617 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Gustaf Ullbergcb307262019-10-29 08:30:44618 StreamConfig(output_sample_rate_hz_, num_output_channels_),
Jonas Olssona4d87372019-07-05 17:08:33619 float_cb_->channels());
andrew@webrtc.org17e40642014-03-04 20:58:13620}
621
andrew@webrtc.orga8b97372014-03-10 22:26:12622int ApmTest::AnalyzeReverseStreamChooser(Format format) {
623 if (format == kIntFormat) {
Per Åhgren2507f8c2020-03-19 11:33:29624 return apm_->ProcessReverseStream(
625 revframe_.data.data(),
626 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
627 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
628 revframe_.data.data());
andrew@webrtc.org17e40642014-03-04 20:58:13629 }
andrew@webrtc.org17e40642014-03-04 20:58:13630 return apm_->AnalyzeReverseStream(
Gustaf Ullbergcb307262019-10-29 08:30:44631 revfloat_cb_->channels(),
Per Åhgren2507f8c2020-03-19 11:33:29632 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels));
andrew@webrtc.org17e40642014-03-04 20:58:13633}
634
Jonas Olssona4d87372019-07-05 17:08:33635void ApmTest::ProcessDelayVerificationTest(int delay_ms,
636 int system_delay_ms,
637 int delay_min,
638 int delay_max) {
Artem Titov0b489302021-07-28 18:50:03639 // The `revframe_` and `frame_` should include the proper frame information,
bjornv@webrtc.org3e102492013-02-14 15:29:09640 // hence can be used for extracting information.
Per Åhgren2507f8c2020-03-19 11:33:29641 Int16FrameData tmp_frame;
642 std::queue<Int16FrameData*> frame_queue;
bjornv@webrtc.org3e102492013-02-14 15:29:09643 bool causal = true;
644
Sam Zackrisson70770ac2019-10-25 08:56:53645 tmp_frame.CopyFrom(revframe_);
bjornv@webrtc.org3e102492013-02-14 15:29:09646 SetFrameTo(&tmp_frame, 0);
647
648 EXPECT_EQ(apm_->kNoError, apm_->Initialize());
Artem Titov0b489302021-07-28 18:50:03649 // Initialize the `frame_queue` with empty frames.
bjornv@webrtc.org3e102492013-02-14 15:29:09650 int frame_delay = delay_ms / 10;
651 while (frame_delay < 0) {
Per Åhgren2507f8c2020-03-19 11:33:29652 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09653 frame->CopyFrom(tmp_frame);
654 frame_queue.push(frame);
655 frame_delay++;
656 causal = false;
657 }
658 while (frame_delay > 0) {
Per Åhgren2507f8c2020-03-19 11:33:29659 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09660 frame->CopyFrom(tmp_frame);
661 frame_queue.push(frame);
662 frame_delay--;
663 }
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34664 // Run for 4.5 seconds, skipping statistics from the first 2.5 seconds. We
665 // need enough frames with audio to have reliable estimates, but as few as
666 // possible to keep processing time down. 4.5 seconds seemed to be a good
667 // compromise for this recording.
bjornv@webrtc.org3e102492013-02-14 15:29:09668 for (int frame_count = 0; frame_count < 450; ++frame_count) {
Per Åhgren2507f8c2020-03-19 11:33:29669 Int16FrameData* frame = new Int16FrameData();
bjornv@webrtc.org3e102492013-02-14 15:29:09670 frame->CopyFrom(tmp_frame);
671 // Use the near end recording, since that has more speech in it.
672 ASSERT_TRUE(ReadFrame(near_file_, frame));
673 frame_queue.push(frame);
Per Åhgren2507f8c2020-03-19 11:33:29674 Int16FrameData* reverse_frame = frame;
675 Int16FrameData* process_frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09676 if (!causal) {
677 reverse_frame = frame_queue.front();
678 // When we call ProcessStream() the frame is modified, so we can't use the
679 // pointer directly when things are non-causal. Use an intermediate frame
680 // and copy the data.
681 process_frame = &tmp_frame;
682 process_frame->CopyFrom(*frame);
683 }
Per Åhgren2507f8c2020-03-19 11:33:29684 EXPECT_EQ(apm_->kNoError, apm_->ProcessReverseStream(
685 reverse_frame->data.data(),
686 StreamConfig(reverse_frame->sample_rate_hz,
687 reverse_frame->num_channels),
688 StreamConfig(reverse_frame->sample_rate_hz,
689 reverse_frame->num_channels),
690 reverse_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09691 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(system_delay_ms));
Per Åhgren2507f8c2020-03-19 11:33:29692 EXPECT_EQ(apm_->kNoError,
693 apm_->ProcessStream(process_frame->data.data(),
694 StreamConfig(process_frame->sample_rate_hz,
695 process_frame->num_channels),
696 StreamConfig(process_frame->sample_rate_hz,
697 process_frame->num_channels),
Per Åhgrendc5522b2020-03-19 13:55:58698 process_frame->data.data()));
bjornv@webrtc.org3e102492013-02-14 15:29:09699 frame = frame_queue.front();
700 frame_queue.pop();
701 delete frame;
702
bjornv@webrtc.orgbbd47fc2014-01-13 08:54:34703 if (frame_count == 250) {
bjornv@webrtc.org3e102492013-02-14 15:29:09704 // Discard the first delay metrics to avoid convergence effects.
Per Åhgrencf4c8722019-12-30 13:32:14705 static_cast<void>(apm_->GetStatistics());
bjornv@webrtc.org3e102492013-02-14 15:29:09706 }
707 }
708
709 rewind(near_file_);
710 while (!frame_queue.empty()) {
Per Åhgren2507f8c2020-03-19 11:33:29711 Int16FrameData* frame = frame_queue.front();
bjornv@webrtc.org3e102492013-02-14 15:29:09712 frame_queue.pop();
713 delete frame;
714 }
715 // Calculate expected delay estimate and acceptable regions. Further,
716 // limit them w.r.t. AEC delay estimation support.
Peter Kastingdce40cf2015-08-24 21:52:23717 const size_t samples_per_ms =
Per Åhgren2507f8c2020-03-19 11:33:29718 rtc::SafeMin<size_t>(16u, frame_.samples_per_channel / 10);
kwiberg07038562017-06-12 18:40:47719 const int expected_median =
720 rtc::SafeClamp<int>(delay_ms - system_delay_ms, delay_min, delay_max);
721 const int expected_median_high = rtc::SafeClamp<int>(
722 expected_median + rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 21:52:23723 delay_max);
kwiberg07038562017-06-12 18:40:47724 const int expected_median_low = rtc::SafeClamp<int>(
725 expected_median - rtc::dchecked_cast<int>(96 / samples_per_ms), delay_min,
Peter Kastingdce40cf2015-08-24 21:52:23726 delay_max);
bjornv@webrtc.org3e102492013-02-14 15:29:09727 // Verify delay metrics.
Per Åhgrencf4c8722019-12-30 13:32:14728 AudioProcessingStats stats = apm_->GetStatistics();
Sam Zackrissoncdf0e6d2018-09-17 09:05:17729 ASSERT_TRUE(stats.delay_median_ms.has_value());
730 int32_t median = *stats.delay_median_ms;
bjornv@webrtc.org3e102492013-02-14 15:29:09731 EXPECT_GE(expected_median_high, median);
732 EXPECT_LE(expected_median_low, median);
733}
734
andrew@webrtc.orga8b97372014-03-10 22:26:12735void ApmTest::StreamParametersTest(Format format) {
niklase@google.com470e71d2011-07-07 08:21:25736 // No errors when the components are disabled.
andrew@webrtc.orga8b97372014-03-10 22:26:12737 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25738
andrew@webrtc.org1e916932011-11-29 18:28:57739 // -- Missing AGC level --
Sam Zackrisson41478c72019-10-15 08:10:26740 AudioProcessing::Config apm_config = apm_->GetConfig();
741 apm_config.gain_controller1.enabled = true;
742 apm_->ApplyConfig(apm_config);
Jonas Olssona4d87372019-07-05 17:08:33743 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25744
andrew@webrtc.org1e916932011-11-29 18:28:57745 // Resets after successful ProcessStream().
Sam Zackrisson41478c72019-10-15 08:10:26746 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12747 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Jonas Olssona4d87372019-07-05 17:08:33748 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25749
andrew@webrtc.org1e916932011-11-29 18:28:57750 // Other stream parameters set correctly.
Sam Zackrissoncdf0e6d2018-09-17 09:05:17751 apm_config.echo_canceller.enabled = true;
752 apm_config.echo_canceller.mobile_mode = false;
753 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57754 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Jonas Olssona4d87372019-07-05 17:08:33755 EXPECT_EQ(apm_->kStreamParameterNotSetError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 08:10:26756 apm_config.gain_controller1.enabled = false;
757 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57758
759 // -- Missing delay --
andrew@webrtc.orga8b97372014-03-10 22:26:12760 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba1c2019-03-06 03:16:46761 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57762
763 // Resets after successful ProcessStream().
764 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
andrew@webrtc.orga8b97372014-03-10 22:26:12765 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Per Åhgren200feba1c2019-03-06 03:16:46766 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org1e916932011-11-29 18:28:57767
768 // Other stream parameters set correctly.
Sam Zackrisson41478c72019-10-15 08:10:26769 apm_config.gain_controller1.enabled = true;
770 apm_->ApplyConfig(apm_config);
771 apm_->set_stream_analog_level(127);
Per Åhgren200feba1c2019-03-06 03:16:46772 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
Sam Zackrisson41478c72019-10-15 08:10:26773 apm_config.gain_controller1.enabled = false;
774 apm_->ApplyConfig(apm_config);
andrew@webrtc.org1e916932011-11-29 18:28:57775
andrew@webrtc.org1e916932011-11-29 18:28:57776 // -- No stream parameters --
Jonas Olssona4d87372019-07-05 17:08:33777 EXPECT_EQ(apm_->kNoError, AnalyzeReverseStreamChooser(format));
Per Åhgren200feba1c2019-03-06 03:16:46778 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
niklase@google.com470e71d2011-07-07 08:21:25779
andrew@webrtc.org1e916932011-11-29 18:28:57780 // -- All there --
niklase@google.com470e71d2011-07-07 08:21:25781 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(100));
Sam Zackrisson41478c72019-10-15 08:10:26782 apm_->set_stream_analog_level(127);
andrew@webrtc.orga8b97372014-03-10 22:26:12783 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(format));
andrew@webrtc.org17e40642014-03-04 20:58:13784}
785
786TEST_F(ApmTest, StreamParametersInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:12787 StreamParametersTest(kIntFormat);
andrew@webrtc.org17e40642014-03-04 20:58:13788}
789
790TEST_F(ApmTest, StreamParametersFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:12791 StreamParametersTest(kFloatFormat);
niklase@google.com470e71d2011-07-07 08:21:25792}
793
Michael Graczyk86c6d332015-07-23 18:41:39794void ApmTest::TestChangingChannelsInt16Interface(
Peter Kasting69558702016-01-13 00:26:35795 size_t num_channels,
Michael Graczyk86c6d332015-07-23 18:41:39796 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 11:33:29797 frame_.num_channels = num_channels;
798
799 EXPECT_EQ(expected_return,
800 apm_->ProcessStream(
801 frame_.data.data(),
802 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
803 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:58804 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 11:33:29805 EXPECT_EQ(expected_return,
806 apm_->ProcessReverseStream(
807 frame_.data.data(),
808 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
809 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
810 frame_.data.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09811}
812
Michael Graczyk86c6d332015-07-23 18:41:39813void ApmTest::TestChangingForwardChannels(
Peter Kasting69558702016-01-13 00:26:35814 size_t num_in_channels,
815 size_t num_out_channels,
Michael Graczyk86c6d332015-07-23 18:41:39816 AudioProcessing::Error expected_return) {
Per Åhgren2507f8c2020-03-19 11:33:29817 const StreamConfig input_stream = {frame_.sample_rate_hz, num_in_channels};
Michael Graczyk86c6d332015-07-23 18:41:39818 const StreamConfig output_stream = {output_sample_rate_hz_, num_out_channels};
819
820 EXPECT_EQ(expected_return,
821 apm_->ProcessStream(float_cb_->channels(), input_stream,
822 output_stream, float_cb_->channels()));
823}
824
825void ApmTest::TestChangingReverseChannels(
Peter Kasting69558702016-01-13 00:26:35826 size_t num_rev_channels,
Michael Graczyk86c6d332015-07-23 18:41:39827 AudioProcessing::Error expected_return) {
828 const ProcessingConfig processing_config = {
Per Åhgren2507f8c2020-03-19 11:33:29829 {{frame_.sample_rate_hz, apm_->num_input_channels()},
ekmeyerson60d9b332015-08-14 17:35:55830 {output_sample_rate_hz_, apm_->num_output_channels()},
Per Åhgren2507f8c2020-03-19 11:33:29831 {frame_.sample_rate_hz, num_rev_channels},
832 {frame_.sample_rate_hz, num_rev_channels}}};
Michael Graczyk86c6d332015-07-23 18:41:39833
ekmeyerson60d9b332015-08-14 17:35:55834 EXPECT_EQ(
835 expected_return,
836 apm_->ProcessReverseStream(
837 float_cb_->channels(), processing_config.reverse_input_stream(),
838 processing_config.reverse_output_stream(), float_cb_->channels()));
Michael Graczyk86c6d332015-07-23 18:41:39839}
840
841TEST_F(ApmTest, ChannelsInt16Interface) {
842 // Testing number of invalid and valid channels.
843 Init(16000, 16000, 16000, 4, 4, 4, false);
844
845 TestChangingChannelsInt16Interface(0, apm_->kBadNumberChannelsError);
846
Peter Kasting69558702016-01-13 00:26:35847 for (size_t i = 1; i < 4; i++) {
Michael Graczyk86c6d332015-07-23 18:41:39848 TestChangingChannelsInt16Interface(i, kNoErr);
niklase@google.com470e71d2011-07-07 08:21:25849 EXPECT_EQ(i, apm_->num_input_channels());
niklase@google.com470e71d2011-07-07 08:21:25850 }
851}
852
Michael Graczyk86c6d332015-07-23 18:41:39853TEST_F(ApmTest, Channels) {
854 // Testing number of invalid and valid channels.
855 Init(16000, 16000, 16000, 4, 4, 4, false);
856
857 TestChangingForwardChannels(0, 1, apm_->kBadNumberChannelsError);
858 TestChangingReverseChannels(0, apm_->kBadNumberChannelsError);
859
Peter Kasting69558702016-01-13 00:26:35860 for (size_t i = 1; i < 4; ++i) {
861 for (size_t j = 0; j < 1; ++j) {
Michael Graczyk86c6d332015-07-23 18:41:39862 // Output channels much be one or match input channels.
863 if (j == 1 || i == j) {
864 TestChangingForwardChannels(i, j, kNoErr);
865 TestChangingReverseChannels(i, kNoErr);
866
867 EXPECT_EQ(i, apm_->num_input_channels());
868 EXPECT_EQ(j, apm_->num_output_channels());
869 // The number of reverse channels used for processing to is always 1.
Peter Kasting69558702016-01-13 00:26:35870 EXPECT_EQ(1u, apm_->num_reverse_channels());
Michael Graczyk86c6d332015-07-23 18:41:39871 } else {
872 TestChangingForwardChannels(i, j,
873 AudioProcessing::kBadNumberChannelsError);
874 }
875 }
876 }
877}
878
andrew@webrtc.orgddbb8a22014-04-22 21:00:04879TEST_F(ApmTest, SampleRatesInt) {
Sam Zackrisson12e319a2020-01-03 13:54:20880 // Testing some valid sample rates.
881 for (int sample_rate : {8000, 12000, 16000, 32000, 44100, 48000, 96000}) {
882 SetContainerFormat(sample_rate, 2, &frame_, &float_cb_);
andrew@webrtc.orgddbb8a22014-04-22 21:00:04883 EXPECT_NOERR(ProcessStreamChooser(kIntFormat));
niklase@google.com470e71d2011-07-07 08:21:25884 }
885}
886
Sam Zackrissone277bde2019-10-25 08:07:54887// This test repeatedly reconfigures the pre-amplifier in APM, processes a
888// number of frames, and checks that output signal has the right level.
889TEST_F(ApmTest, PreAmplifier) {
890 // Fill the audio frame with a sawtooth pattern.
Sam Zackrisson70770ac2019-10-25 08:56:53891 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
Per Åhgren2507f8c2020-03-19 11:33:29892 const size_t samples_per_channel = frame_.samples_per_channel;
Sam Zackrissone277bde2019-10-25 08:07:54893 for (size_t i = 0; i < samples_per_channel; i++) {
Per Åhgren2507f8c2020-03-19 11:33:29894 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
Sam Zackrissone277bde2019-10-25 08:07:54895 frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
896 }
897 }
898 // Cache the frame in tmp_frame.
Per Åhgren2507f8c2020-03-19 11:33:29899 Int16FrameData tmp_frame;
Sam Zackrisson70770ac2019-10-25 08:56:53900 tmp_frame.CopyFrom(frame_);
Sam Zackrissone277bde2019-10-25 08:07:54901
Per Åhgren2507f8c2020-03-19 11:33:29902 auto compute_power = [](const Int16FrameData& frame) {
Sam Zackrissone277bde2019-10-25 08:07:54903 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
904 return std::accumulate(data.begin(), data.end(), 0.0f,
905 [](float a, float b) { return a + b * b; }) /
906 data.size() / 32768 / 32768;
907 };
908
909 const float input_power = compute_power(tmp_frame);
910 // Double-check that the input data is large compared to the error kEpsilon.
911 constexpr float kEpsilon = 1e-4f;
912 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
913
914 // 1. Enable pre-amp with 0 dB gain.
915 AudioProcessing::Config config = apm_->GetConfig();
916 config.pre_amplifier.enabled = true;
917 config.pre_amplifier.fixed_gain_factor = 1.0f;
918 apm_->ApplyConfig(config);
919
920 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:53921 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 08:07:54922 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
923 }
Sam Zackrisson70770ac2019-10-25 08:56:53924 float output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 08:07:54925 EXPECT_NEAR(output_power, input_power, kEpsilon);
926 config = apm_->GetConfig();
927 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
928
929 // 2. Change pre-amp gain via ApplyConfig.
930 config.pre_amplifier.fixed_gain_factor = 2.0f;
931 apm_->ApplyConfig(config);
932
933 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:53934 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 08:07:54935 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
936 }
Sam Zackrisson70770ac2019-10-25 08:56:53937 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 08:07:54938 EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
939 config = apm_->GetConfig();
940 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
941
942 // 3. Change pre-amp gain via a RuntimeSetting.
943 apm_->SetRuntimeSetting(
944 AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
945
946 for (int i = 0; i < 20; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:53947 frame_.CopyFrom(tmp_frame);
Sam Zackrissone277bde2019-10-25 08:07:54948 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
949 }
Sam Zackrisson70770ac2019-10-25 08:56:53950 output_power = compute_power(frame_);
Sam Zackrissone277bde2019-10-25 08:07:54951 EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
952 config = apm_->GetConfig();
953 EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
954}
955
Alessio Bazzicafcf1af32022-09-07 15:14:26956// Ensures that the emulated analog mic gain functionality runs without
957// crashing.
Per Åhgrendb5d7282021-03-15 16:31:04958TEST_F(ApmTest, AnalogMicGainEmulation) {
959 // Fill the audio frame with a sawtooth pattern.
960 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
961 const size_t samples_per_channel = frame_.samples_per_channel;
962 for (size_t i = 0; i < samples_per_channel; i++) {
963 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
964 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
965 }
966 }
967 // Cache the frame in tmp_frame.
968 Int16FrameData tmp_frame;
969 tmp_frame.CopyFrom(frame_);
970
971 // Enable the analog gain emulation.
972 AudioProcessing::Config config = apm_->GetConfig();
973 config.capture_level_adjustment.enabled = true;
974 config.capture_level_adjustment.analog_mic_gain_emulation.enabled = true;
975 config.capture_level_adjustment.analog_mic_gain_emulation.initial_level = 21;
976 config.gain_controller1.enabled = true;
977 config.gain_controller1.mode =
978 AudioProcessing::Config::GainController1::Mode::kAdaptiveAnalog;
979 config.gain_controller1.analog_gain_controller.enabled = true;
980 apm_->ApplyConfig(config);
981
982 // Process a number of frames to ensure that the code runs without crashes.
983 for (int i = 0; i < 20; ++i) {
984 frame_.CopyFrom(tmp_frame);
985 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
986 }
987}
988
989// This test repeatedly reconfigures the capture level adjustment functionality
990// in APM, processes a number of frames, and checks that output signal has the
991// right level.
992TEST_F(ApmTest, CaptureLevelAdjustment) {
993 // Fill the audio frame with a sawtooth pattern.
994 rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(&frame_);
995 const size_t samples_per_channel = frame_.samples_per_channel;
996 for (size_t i = 0; i < samples_per_channel; i++) {
997 for (size_t ch = 0; ch < frame_.num_channels; ++ch) {
998 frame_data[i + ch * samples_per_channel] = 100 * ((i % 3) - 1);
999 }
1000 }
1001 // Cache the frame in tmp_frame.
1002 Int16FrameData tmp_frame;
1003 tmp_frame.CopyFrom(frame_);
1004
1005 auto compute_power = [](const Int16FrameData& frame) {
1006 rtc::ArrayView<const int16_t> data = GetFrameData(frame);
1007 return std::accumulate(data.begin(), data.end(), 0.0f,
1008 [](float a, float b) { return a + b * b; }) /
1009 data.size() / 32768 / 32768;
1010 };
1011
1012 const float input_power = compute_power(tmp_frame);
1013 // Double-check that the input data is large compared to the error kEpsilon.
1014 constexpr float kEpsilon = 1e-20f;
1015 RTC_DCHECK_GE(input_power, 10 * kEpsilon);
1016
1017 // 1. Enable pre-amp with 0 dB gain.
1018 AudioProcessing::Config config = apm_->GetConfig();
1019 config.capture_level_adjustment.enabled = true;
1020 config.capture_level_adjustment.pre_gain_factor = 0.5f;
1021 config.capture_level_adjustment.post_gain_factor = 4.f;
1022 const float expected_output_power1 =
1023 config.capture_level_adjustment.pre_gain_factor *
1024 config.capture_level_adjustment.pre_gain_factor *
1025 config.capture_level_adjustment.post_gain_factor *
1026 config.capture_level_adjustment.post_gain_factor * input_power;
1027 apm_->ApplyConfig(config);
1028
1029 for (int i = 0; i < 20; ++i) {
1030 frame_.CopyFrom(tmp_frame);
1031 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1032 }
1033 float output_power = compute_power(frame_);
1034 EXPECT_NEAR(output_power, expected_output_power1, kEpsilon);
1035 config = apm_->GetConfig();
1036 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1037 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 4.f);
1038
1039 // 2. Change pre-amp gain via ApplyConfig.
1040 config.capture_level_adjustment.pre_gain_factor = 1.0f;
1041 config.capture_level_adjustment.post_gain_factor = 2.f;
1042 const float expected_output_power2 =
1043 config.capture_level_adjustment.pre_gain_factor *
1044 config.capture_level_adjustment.pre_gain_factor *
1045 config.capture_level_adjustment.post_gain_factor *
1046 config.capture_level_adjustment.post_gain_factor * input_power;
1047 apm_->ApplyConfig(config);
1048
1049 for (int i = 0; i < 20; ++i) {
1050 frame_.CopyFrom(tmp_frame);
1051 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1052 }
1053 output_power = compute_power(frame_);
1054 EXPECT_NEAR(output_power, expected_output_power2, kEpsilon);
1055 config = apm_->GetConfig();
1056 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 1.0f);
1057 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 2.f);
1058
1059 // 3. Change pre-amp gain via a RuntimeSetting.
1060 constexpr float kPreGain3 = 0.5f;
1061 constexpr float kPostGain3 = 3.f;
1062 const float expected_output_power3 =
1063 kPreGain3 * kPreGain3 * kPostGain3 * kPostGain3 * input_power;
1064
1065 apm_->SetRuntimeSetting(
1066 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kPreGain3));
1067 apm_->SetRuntimeSetting(
1068 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kPostGain3));
1069
1070 for (int i = 0; i < 20; ++i) {
1071 frame_.CopyFrom(tmp_frame);
1072 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
1073 }
1074 output_power = compute_power(frame_);
1075 EXPECT_NEAR(output_power, expected_output_power3, kEpsilon);
1076 config = apm_->GetConfig();
1077 EXPECT_EQ(config.capture_level_adjustment.pre_gain_factor, 0.5f);
1078 EXPECT_EQ(config.capture_level_adjustment.post_gain_factor, 3.f);
1079}
1080
aluebs@webrtc.orgc9ee4122014-02-03 14:41:571081TEST_F(ApmTest, GainControl) {
Sam Zackrisson41478c72019-10-15 08:10:261082 AudioProcessing::Config config = apm_->GetConfig();
1083 config.gain_controller1.enabled = false;
1084 apm_->ApplyConfig(config);
1085 config.gain_controller1.enabled = true;
1086 apm_->ApplyConfig(config);
1087
niklase@google.com470e71d2011-07-07 08:21:251088 // Testing gain modes
Sam Zackrisson41478c72019-10-15 08:10:261089 for (auto mode :
1090 {AudioProcessing::Config::GainController1::kAdaptiveDigital,
1091 AudioProcessing::Config::GainController1::kFixedDigital,
1092 AudioProcessing::Config::GainController1::kAdaptiveAnalog}) {
1093 config.gain_controller1.mode = mode;
1094 apm_->ApplyConfig(config);
1095 apm_->set_stream_analog_level(100);
1096 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:251097 }
niklase@google.com470e71d2011-07-07 08:21:251098
Sam Zackrisson41478c72019-10-15 08:10:261099 // Testing target levels
1100 for (int target_level_dbfs : {0, 15, 31}) {
1101 config.gain_controller1.target_level_dbfs = target_level_dbfs;
1102 apm_->ApplyConfig(config);
1103 apm_->set_stream_analog_level(100);
1104 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:251105 }
1106
Sam Zackrissonf0d1c032019-03-27 12:28:081107 // Testing compression gains
Sam Zackrisson41478c72019-10-15 08:10:261108 for (int compression_gain_db : {0, 10, 90}) {
1109 config.gain_controller1.compression_gain_db = compression_gain_db;
1110 apm_->ApplyConfig(config);
1111 apm_->set_stream_analog_level(100);
1112 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:251113 }
1114
1115 // Testing limiter off/on
Sam Zackrisson41478c72019-10-15 08:10:261116 for (bool enable : {false, true}) {
1117 config.gain_controller1.enable_limiter = enable;
1118 apm_->ApplyConfig(config);
1119 apm_->set_stream_analog_level(100);
1120 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1121 }
niklase@google.com470e71d2011-07-07 08:21:251122
Hanna Silencd597042021-11-02 10:02:481123 // Testing level limits.
1124 constexpr int kMinLevel = 0;
1125 constexpr int kMaxLevel = 255;
1126 apm_->set_stream_analog_level(kMinLevel);
1127 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1128 apm_->set_stream_analog_level((kMinLevel + kMaxLevel) / 2);
1129 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
1130 apm_->set_stream_analog_level(kMaxLevel);
1131 EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kFloatFormat));
niklase@google.com470e71d2011-07-07 08:21:251132}
1133
Sam Zackrissonf0d1c032019-03-27 12:28:081134#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
Tommia5e07cc2020-05-26 19:40:371135using ApmDeathTest = ApmTest;
1136
1137TEST_F(ApmDeathTest, GainControlDiesOnTooLowTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 08:10:261138 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131139 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261140 config.gain_controller1.target_level_dbfs = -1;
1141 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081142}
1143
Tommia5e07cc2020-05-26 19:40:371144TEST_F(ApmDeathTest, GainControlDiesOnTooHighTargetLevelDbfs) {
Sam Zackrisson41478c72019-10-15 08:10:261145 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131146 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261147 config.gain_controller1.target_level_dbfs = 32;
1148 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081149}
1150
Tommia5e07cc2020-05-26 19:40:371151TEST_F(ApmDeathTest, GainControlDiesOnTooLowCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 08:10:261152 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131153 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261154 config.gain_controller1.compression_gain_db = -1;
1155 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081156}
1157
Tommia5e07cc2020-05-26 19:40:371158TEST_F(ApmDeathTest, GainControlDiesOnTooHighCompressionGainDb) {
Sam Zackrisson41478c72019-10-15 08:10:261159 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131160 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261161 config.gain_controller1.compression_gain_db = 91;
1162 EXPECT_DEATH(apm_->ApplyConfig(config), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081163}
1164
Tommia5e07cc2020-05-26 19:40:371165TEST_F(ApmDeathTest, ApmDiesOnTooLowAnalogLevel) {
Sam Zackrisson41478c72019-10-15 08:10:261166 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131167 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261168 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 10:02:481169 EXPECT_DEATH(apm_->set_stream_analog_level(-1), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081170}
1171
Tommia5e07cc2020-05-26 19:40:371172TEST_F(ApmDeathTest, ApmDiesOnTooHighAnalogLevel) {
Sam Zackrisson41478c72019-10-15 08:10:261173 auto config = apm_->GetConfig();
Per Åhgren0695df12020-01-13 13:43:131174 config.gain_controller1.enabled = true;
Sam Zackrisson41478c72019-10-15 08:10:261175 apm_->ApplyConfig(config);
Hanna Silencd597042021-11-02 10:02:481176 EXPECT_DEATH(apm_->set_stream_analog_level(256), "");
Sam Zackrissonf0d1c032019-03-27 12:28:081177}
1178#endif
1179
andrew@webrtc.org27c69802014-02-18 20:24:561180void ApmTest::RunQuantizedVolumeDoesNotGetStuckTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041181 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 08:10:261182 auto config = apm_->GetConfig();
1183 config.gain_controller1.enabled = true;
1184 config.gain_controller1.mode =
1185 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1186 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:561187
1188 int out_analog_level = 0;
1189 for (int i = 0; i < 2000; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:531190 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:561191 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 08:56:531192 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:561193
1194 // Always pass in the same volume.
Sam Zackrisson41478c72019-10-15 08:10:261195 apm_->set_stream_analog_level(100);
Per Åhgren2507f8c2020-03-19 11:33:291196 EXPECT_EQ(apm_->kNoError,
1197 apm_->ProcessStream(
1198 frame_.data.data(),
1199 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1200 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581201 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 08:10:261202 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:561203 }
1204
1205 // Ensure the AGC is still able to reach the maximum.
1206 EXPECT_EQ(255, out_analog_level);
1207}
1208
1209// Verifies that despite volume slider quantization, the AGC can continue to
1210// increase its volume.
1211TEST_F(ApmTest, QuantizedVolumeDoesNotGetStuck) {
Sam Zackrisson3bd444f2022-08-03 12:37:001212 for (size_t sample_rate_hz : kProcessSampleRates) {
1213 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1214 RunQuantizedVolumeDoesNotGetStuckTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:561215 }
1216}
1217
1218void ApmTest::RunManualVolumeChangeIsPossibleTest(int sample_rate) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041219 Init(sample_rate, sample_rate, sample_rate, 2, 2, 2, false);
Sam Zackrisson41478c72019-10-15 08:10:261220 auto config = apm_->GetConfig();
1221 config.gain_controller1.enabled = true;
1222 config.gain_controller1.mode =
1223 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1224 apm_->ApplyConfig(config);
andrew@webrtc.org27c69802014-02-18 20:24:561225
1226 int out_analog_level = 100;
1227 for (int i = 0; i < 1000; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:531228 ReadFrameWithRewind(near_file_, &frame_);
andrew@webrtc.org27c69802014-02-18 20:24:561229 // Ensure the audio is at a low level, so the AGC will try to increase it.
Sam Zackrisson70770ac2019-10-25 08:56:531230 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:561231
Sam Zackrisson41478c72019-10-15 08:10:261232 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 11:33:291233 EXPECT_EQ(apm_->kNoError,
1234 apm_->ProcessStream(
1235 frame_.data.data(),
1236 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1237 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581238 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 08:10:261239 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:561240 }
1241
1242 // Ensure the volume was raised.
1243 EXPECT_GT(out_analog_level, 100);
1244 int highest_level_reached = out_analog_level;
1245 // Simulate a user manual volume change.
1246 out_analog_level = 100;
1247
1248 for (int i = 0; i < 300; ++i) {
Sam Zackrisson70770ac2019-10-25 08:56:531249 ReadFrameWithRewind(near_file_, &frame_);
1250 ScaleFrame(&frame_, 0.25);
andrew@webrtc.org27c69802014-02-18 20:24:561251
Sam Zackrisson41478c72019-10-15 08:10:261252 apm_->set_stream_analog_level(out_analog_level);
Per Åhgren2507f8c2020-03-19 11:33:291253 EXPECT_EQ(apm_->kNoError,
1254 apm_->ProcessStream(
1255 frame_.data.data(),
1256 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1257 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581258 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 08:10:261259 out_analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org27c69802014-02-18 20:24:561260 // Check that AGC respected the manually adjusted volume.
1261 EXPECT_LT(out_analog_level, highest_level_reached);
1262 }
1263 // Check that the volume was still raised.
1264 EXPECT_GT(out_analog_level, 100);
1265}
1266
1267TEST_F(ApmTest, ManualVolumeChangeIsPossible) {
Sam Zackrisson3bd444f2022-08-03 12:37:001268 for (size_t sample_rate_hz : kProcessSampleRates) {
1269 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1270 RunManualVolumeChangeIsPossibleTest(sample_rate_hz);
andrew@webrtc.org27c69802014-02-18 20:24:561271 }
1272}
1273
niklase@google.com470e71d2011-07-07 08:21:251274TEST_F(ApmTest, HighPassFilter) {
andrew@webrtc.org648af742012-02-08 01:57:291275 // Turn HP filter on/off
peah8271d042016-11-22 15:24:521276 AudioProcessing::Config apm_config;
1277 apm_config.high_pass_filter.enabled = true;
1278 apm_->ApplyConfig(apm_config);
1279 apm_config.high_pass_filter.enabled = false;
1280 apm_->ApplyConfig(apm_config);
niklase@google.com470e71d2011-07-07 08:21:251281}
1282
andrew@webrtc.orgecac9b72012-05-02 00:04:101283TEST_F(ApmTest, AllProcessingDisabledByDefault) {
Sam Zackrissoncdf0e6d2018-09-17 09:05:171284 AudioProcessing::Config config = apm_->GetConfig();
1285 EXPECT_FALSE(config.echo_canceller.enabled);
1286 EXPECT_FALSE(config.high_pass_filter.enabled);
Sam Zackrisson41478c72019-10-15 08:10:261287 EXPECT_FALSE(config.gain_controller1.enabled);
saza0bad15f2019-10-16 09:46:111288 EXPECT_FALSE(config.noise_suppression.enabled);
andrew@webrtc.orgecac9b72012-05-02 00:04:101289}
1290
Sam Zackrisson3bd444f2022-08-03 12:37:001291TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledInt) {
1292 // Test that ProcessStream simply copies input to output when all components
1293 // are disabled.
1294 // Runs over all processing rates, and some particularly common or special
1295 // rates.
1296 // - 8000 Hz: lowest sample rate seen in Chrome metrics,
1297 // - 22050 Hz: APM input/output frames are not exactly 10 ms,
1298 // - 44100 Hz: very common desktop sample rate.
1299 constexpr int kSampleRatesHz[] = {8000, 16000, 22050, 32000, 44100, 48000};
1300 for (size_t sample_rate_hz : kSampleRatesHz) {
1301 SCOPED_TRACE(::testing::Message() << "sample_rate_hz=" << sample_rate_hz);
1302 Init(sample_rate_hz, sample_rate_hz, sample_rate_hz, 2, 2, 2, false);
Sam Zackrisson70770ac2019-10-25 08:56:531303 SetFrameTo(&frame_, 1000, 2000);
Per Åhgren2507f8c2020-03-19 11:33:291304 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 08:56:531305 frame_copy.CopyFrom(frame_);
andrew@webrtc.orgecac9b72012-05-02 00:04:101306 for (int j = 0; j < 1000; j++) {
Per Åhgren2507f8c2020-03-19 11:33:291307 EXPECT_EQ(apm_->kNoError,
1308 apm_->ProcessStream(
1309 frame_.data.data(),
1310 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1311 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581312 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 08:56:531313 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
Per Åhgren2507f8c2020-03-19 11:33:291314 EXPECT_EQ(apm_->kNoError,
1315 apm_->ProcessReverseStream(
1316 frame_.data.data(),
1317 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1318 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1319 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 08:56:531320 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.orgecac9b72012-05-02 00:04:101321 }
1322 }
1323}
1324
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:541325TEST_F(ApmTest, NoProcessingWhenAllComponentsDisabledFloat) {
Sam Zackrisson3bd444f2022-08-03 12:37:001326 // Test that ProcessStream simply copies input to output when all components
1327 // are disabled.
Per Åhgrenc8626b62019-08-23 13:49:511328 const size_t kSamples = 160;
1329 const int sample_rate = 16000;
Jonas Olssona4d87372019-07-05 17:08:331330 const float src[kSamples] = {-1.0f, 0.0f, 1.0f};
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:541331 float dest[kSamples] = {};
1332
1333 auto src_channels = &src[0];
1334 auto dest_channels = &dest[0];
1335
Niels Möller4f776ac2021-07-02 09:30:541336 apm_ = AudioProcessingBuilderForTesting().Create();
Gustaf Ullbergcb307262019-10-29 08:30:441337 EXPECT_NOERR(apm_->ProcessStream(&src_channels, StreamConfig(sample_rate, 1),
1338 StreamConfig(sample_rate, 1),
1339 &dest_channels));
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:541340
1341 for (size_t i = 0; i < kSamples; ++i) {
1342 EXPECT_EQ(src[i], dest[i]);
1343 }
ekmeyerson60d9b332015-08-14 17:35:551344
1345 // Same for ProcessReverseStream.
1346 float rev_dest[kSamples] = {};
1347 auto rev_dest_channels = &rev_dest[0];
1348
1349 StreamConfig input_stream = {sample_rate, 1};
1350 StreamConfig output_stream = {sample_rate, 1};
1351 EXPECT_NOERR(apm_->ProcessReverseStream(&src_channels, input_stream,
1352 output_stream, &rev_dest_channels));
1353
1354 for (size_t i = 0; i < kSamples; ++i) {
1355 EXPECT_EQ(src[i], rev_dest[i]);
1356 }
mgraczyk@chromium.orgd6e84d92015-01-14 01:33:541357}
1358
andrew@webrtc.org07bf9a02012-05-05 00:32:001359TEST_F(ApmTest, IdenticalInputChannelsResultInIdenticalOutputChannels) {
1360 EnableAllComponents();
1361
pkasting25702cb2016-01-08 21:50:271362 for (size_t i = 0; i < arraysize(kProcessSampleRates); i++) {
Jonas Olssona4d87372019-07-05 17:08:331363 Init(kProcessSampleRates[i], kProcessSampleRates[i], kProcessSampleRates[i],
1364 2, 2, 2, false);
andrew@webrtc.org07bf9a02012-05-05 00:32:001365 int analog_level = 127;
andrew@webrtc.orgddbb8a22014-04-22 21:00:041366 ASSERT_EQ(0, feof(far_file_));
1367 ASSERT_EQ(0, feof(near_file_));
Sam Zackrisson70770ac2019-10-25 08:56:531368 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 11:33:291369 CopyLeftToRightChannel(revframe_.data.data(),
1370 revframe_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:001371
Per Åhgren2507f8c2020-03-19 11:33:291372 ASSERT_EQ(
1373 kNoErr,
1374 apm_->ProcessReverseStream(
1375 revframe_.data.data(),
1376 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1377 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1378 revframe_.data.data()));
andrew@webrtc.org07bf9a02012-05-05 00:32:001379
Per Åhgren2507f8c2020-03-19 11:33:291380 CopyLeftToRightChannel(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:001381
andrew@webrtc.orgddbb8a22014-04-22 21:00:041382 ASSERT_EQ(kNoErr, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 08:10:261383 apm_->set_stream_analog_level(analog_level);
Per Åhgren2507f8c2020-03-19 11:33:291384 ASSERT_EQ(kNoErr,
1385 apm_->ProcessStream(
1386 frame_.data.data(),
1387 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1388 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581389 frame_.data.data()));
Sam Zackrisson41478c72019-10-15 08:10:261390 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org07bf9a02012-05-05 00:32:001391
Per Åhgren2507f8c2020-03-19 11:33:291392 VerifyChannelsAreEqual(frame_.data.data(), frame_.samples_per_channel);
andrew@webrtc.org07bf9a02012-05-05 00:32:001393 }
bjornv@webrtc.org3e102492013-02-14 15:29:091394 rewind(far_file_);
1395 rewind(near_file_);
andrew@webrtc.org07bf9a02012-05-05 00:32:001396 }
1397}
1398
bjornv@webrtc.orgcb0ea432014-06-09 08:21:521399TEST_F(ApmTest, SplittingFilter) {
andrew@webrtc.org755b04a2011-11-15 16:57:561400 // Verify the filter is not active through undistorted audio when:
1401 // 1. No components are enabled...
Sam Zackrisson70770ac2019-10-25 08:56:531402 SetFrameTo(&frame_, 1000);
Per Åhgren2507f8c2020-03-19 11:33:291403 Int16FrameData frame_copy;
Sam Zackrisson70770ac2019-10-25 08:56:531404 frame_copy.CopyFrom(frame_);
Per Åhgren2507f8c2020-03-19 11:33:291405 EXPECT_EQ(apm_->kNoError,
1406 apm_->ProcessStream(
1407 frame_.data.data(),
1408 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1409 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581410 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 11:33:291411 EXPECT_EQ(apm_->kNoError,
1412 apm_->ProcessStream(
1413 frame_.data.data(),
1414 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1415 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581416 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 08:56:531417 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:561418
1419 // 2. Only the level estimator is enabled...
saza6787f232019-10-11 17:31:071420 auto apm_config = apm_->GetConfig();
Sam Zackrisson70770ac2019-10-25 08:56:531421 SetFrameTo(&frame_, 1000);
1422 frame_copy.CopyFrom(frame_);
saza6787f232019-10-11 17:31:071423 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 11:33:291424 EXPECT_EQ(apm_->kNoError,
1425 apm_->ProcessStream(
1426 frame_.data.data(),
1427 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1428 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581429 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 11:33:291430 EXPECT_EQ(apm_->kNoError,
1431 apm_->ProcessStream(
1432 frame_.data.data(),
1433 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1434 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581435 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 08:56:531436 EXPECT_TRUE(FrameDataAreEqual(frame_, frame_copy));
saza6787f232019-10-11 17:31:071437 apm_->ApplyConfig(apm_config);
andrew@webrtc.org755b04a2011-11-15 16:57:561438
Sam Zackrissoncb1b5562018-09-28 12:15:091439 // Check the test is valid. We should have distortion from the filter
1440 // when AEC is enabled (which won't affect the audio).
Sam Zackrissoncdf0e6d2018-09-17 09:05:171441 apm_config.echo_canceller.enabled = true;
1442 apm_config.echo_canceller.mobile_mode = false;
1443 apm_->ApplyConfig(apm_config);
Per Åhgren2507f8c2020-03-19 11:33:291444 frame_.samples_per_channel = 320;
1445 frame_.num_channels = 2;
1446 frame_.sample_rate_hz = 32000;
Sam Zackrisson70770ac2019-10-25 08:56:531447 SetFrameTo(&frame_, 1000);
1448 frame_copy.CopyFrom(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561449 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Per Åhgren2507f8c2020-03-19 11:33:291450 EXPECT_EQ(apm_->kNoError,
1451 apm_->ProcessStream(
1452 frame_.data.data(),
1453 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1454 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581455 frame_.data.data()));
Sam Zackrisson70770ac2019-10-25 08:56:531456 EXPECT_FALSE(FrameDataAreEqual(frame_, frame_copy));
andrew@webrtc.org755b04a2011-11-15 16:57:561457}
1458
andrew@webrtc.orga8b97372014-03-10 22:26:121459#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
Ali Tofighf3592cb2022-08-16 12:44:381460void ApmTest::ProcessDebugDump(absl::string_view in_filename,
1461 absl::string_view out_filename,
ivocd66b44d2016-01-15 11:06:361462 Format format,
1463 int max_size_bytes) {
Danil Chapovalov07122bc2019-03-26 13:37:011464 TaskQueueForTest worker_queue("ApmTest_worker_queue");
Ali Tofighf3592cb2022-08-16 12:44:381465 FILE* in_file = fopen(std::string(in_filename).c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:121466 ASSERT_TRUE(in_file != NULL);
1467 audioproc::Event event_msg;
1468 bool first_init = true;
1469
1470 while (ReadMessageFromFile(in_file, &event_msg)) {
1471 if (event_msg.type() == audioproc::Event::INIT) {
1472 const audioproc::Init msg = event_msg.init();
1473 int reverse_sample_rate = msg.sample_rate();
1474 if (msg.has_reverse_sample_rate()) {
1475 reverse_sample_rate = msg.reverse_sample_rate();
1476 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:041477 int output_sample_rate = msg.sample_rate();
1478 if (msg.has_output_sample_rate()) {
1479 output_sample_rate = msg.output_sample_rate();
1480 }
1481
Jonas Olssona4d87372019-07-05 17:08:331482 Init(msg.sample_rate(), output_sample_rate, reverse_sample_rate,
1483 msg.num_input_channels(), msg.num_output_channels(),
1484 msg.num_reverse_channels(), false);
andrew@webrtc.orga8b97372014-03-10 22:26:121485 if (first_init) {
aleloif4dd1912017-06-15 08:55:381486 // AttachAecDump() writes an additional init message. Don't start
andrew@webrtc.orga8b97372014-03-10 22:26:121487 // recording until after the first init to avoid the extra message.
Danil Chapovalovb64eef12024-01-04 13:45:231488 auto aec_dump = AecDumpFactory::Create(out_filename, max_size_bytes,
1489 worker_queue.Get());
aleloif4dd1912017-06-15 08:55:381490 EXPECT_TRUE(aec_dump);
1491 apm_->AttachAecDump(std::move(aec_dump));
andrew@webrtc.orga8b97372014-03-10 22:26:121492 first_init = false;
1493 }
1494
1495 } else if (event_msg.type() == audioproc::Event::REVERSE_STREAM) {
1496 const audioproc::ReverseStream msg = event_msg.reverse_stream();
1497
1498 if (msg.channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 11:33:291499 ASSERT_EQ(revframe_.num_channels,
Peter Kasting69558702016-01-13 00:26:351500 static_cast<size_t>(msg.channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:121501 for (int i = 0; i < msg.channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 17:08:331502 memcpy(revfloat_cb_->channels()[i], msg.channel(i).data(),
1503 msg.channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:121504 }
1505 } else {
Per Åhgren2507f8c2020-03-19 11:33:291506 memcpy(revframe_.data.data(), msg.data().data(), msg.data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:121507 if (format == kFloatFormat) {
1508 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 08:56:531509 ConvertToFloat(revframe_, revfloat_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:121510 }
1511 }
1512 AnalyzeReverseStreamChooser(format);
1513
1514 } else if (event_msg.type() == audioproc::Event::STREAM) {
1515 const audioproc::Stream msg = event_msg.stream();
1516 // ProcessStream could have changed this for the output frame.
Per Åhgren2507f8c2020-03-19 11:33:291517 frame_.num_channels = apm_->num_input_channels();
andrew@webrtc.orga8b97372014-03-10 22:26:121518
Alessio Bazzica3153b362022-09-05 14:05:241519 apm_->set_stream_analog_level(msg.applied_input_volume());
andrew@webrtc.orga8b97372014-03-10 22:26:121520 EXPECT_NOERR(apm_->set_stream_delay_ms(msg.delay()));
andrew@webrtc.orga8b97372014-03-10 22:26:121521 if (msg.has_keypress()) {
1522 apm_->set_stream_key_pressed(msg.keypress());
1523 } else {
1524 apm_->set_stream_key_pressed(true);
1525 }
1526
1527 if (msg.input_channel_size() > 0) {
Per Åhgren2507f8c2020-03-19 11:33:291528 ASSERT_EQ(frame_.num_channels,
Peter Kasting69558702016-01-13 00:26:351529 static_cast<size_t>(msg.input_channel_size()));
andrew@webrtc.orga8b97372014-03-10 22:26:121530 for (int i = 0; i < msg.input_channel_size(); ++i) {
Jonas Olssona4d87372019-07-05 17:08:331531 memcpy(float_cb_->channels()[i], msg.input_channel(i).data(),
1532 msg.input_channel(i).size());
andrew@webrtc.orga8b97372014-03-10 22:26:121533 }
1534 } else {
Per Åhgren2507f8c2020-03-19 11:33:291535 memcpy(frame_.data.data(), msg.input_data().data(),
yujo36b1a5f2017-06-12 19:45:321536 msg.input_data().size());
andrew@webrtc.orga8b97372014-03-10 22:26:121537 if (format == kFloatFormat) {
1538 // We're using an int16 input file; convert to float.
Sam Zackrisson70770ac2019-10-25 08:56:531539 ConvertToFloat(frame_, float_cb_.get());
andrew@webrtc.orga8b97372014-03-10 22:26:121540 }
1541 }
1542 ProcessStreamChooser(format);
1543 }
1544 }
aleloif4dd1912017-06-15 08:55:381545 apm_->DetachAecDump();
andrew@webrtc.orga8b97372014-03-10 22:26:121546 fclose(in_file);
1547}
1548
1549void ApmTest::VerifyDebugDumpTest(Format format) {
Minyue Li656d6092018-08-10 13:38:521550 rtc::ScopedFakeClock fake_clock;
andrew@webrtc.orga8b97372014-03-10 22:26:121551 const std::string in_filename = test::ResourcePath("ref03", "aecdump");
henrik.lundin@webrtc.org1092ea02014-04-02 07:46:491552 std::string format_string;
1553 switch (format) {
1554 case kIntFormat:
1555 format_string = "_int";
1556 break;
1557 case kFloatFormat:
1558 format_string = "_float";
1559 break;
1560 }
pbos@webrtc.orga525c982015-01-12 17:31:181561 const std::string ref_filename = test::TempFilename(
1562 test::OutputPath(), std::string("ref") + format_string + "_aecdump");
1563 const std::string out_filename = test::TempFilename(
1564 test::OutputPath(), std::string("out") + format_string + "_aecdump");
ivocd66b44d2016-01-15 11:06:361565 const std::string limited_filename = test::TempFilename(
1566 test::OutputPath(), std::string("limited") + format_string + "_aecdump");
1567 const size_t logging_limit_bytes = 100000;
1568 // We expect at least this many bytes in the created logfile.
1569 const size_t logging_expected_bytes = 95000;
andrew@webrtc.orga8b97372014-03-10 22:26:121570 EnableAllComponents();
ivocd66b44d2016-01-15 11:06:361571 ProcessDebugDump(in_filename, ref_filename, format, -1);
1572 ProcessDebugDump(ref_filename, out_filename, format, -1);
1573 ProcessDebugDump(ref_filename, limited_filename, format, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:121574
1575 FILE* ref_file = fopen(ref_filename.c_str(), "rb");
1576 FILE* out_file = fopen(out_filename.c_str(), "rb");
ivocd66b44d2016-01-15 11:06:361577 FILE* limited_file = fopen(limited_filename.c_str(), "rb");
andrew@webrtc.orga8b97372014-03-10 22:26:121578 ASSERT_TRUE(ref_file != NULL);
1579 ASSERT_TRUE(out_file != NULL);
ivocd66b44d2016-01-15 11:06:361580 ASSERT_TRUE(limited_file != NULL);
kwiberg62eaacf2016-02-17 14:39:051581 std::unique_ptr<uint8_t[]> ref_bytes;
1582 std::unique_ptr<uint8_t[]> out_bytes;
1583 std::unique_ptr<uint8_t[]> limited_bytes;
andrew@webrtc.orga8b97372014-03-10 22:26:121584
1585 size_t ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1586 size_t out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 11:06:361587 size_t limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:121588 size_t bytes_read = 0;
ivocd66b44d2016-01-15 11:06:361589 size_t bytes_read_limited = 0;
andrew@webrtc.orga8b97372014-03-10 22:26:121590 while (ref_size > 0 && out_size > 0) {
1591 bytes_read += ref_size;
ivocd66b44d2016-01-15 11:06:361592 bytes_read_limited += limited_size;
andrew@webrtc.orga8b97372014-03-10 22:26:121593 EXPECT_EQ(ref_size, out_size);
ivocd66b44d2016-01-15 11:06:361594 EXPECT_GE(ref_size, limited_size);
Alessio Bazzica85a126e2022-08-11 13:48:541595 EXPECT_TRUE(ExpectMessageEq(/*actual=*/{out_bytes.get(), out_size},
1596 /*expected=*/{ref_bytes.get(), ref_size}));
1597 if (limited_size > 0) {
1598 EXPECT_TRUE(
1599 ExpectMessageEq(/*actual=*/{limited_bytes.get(), limited_size},
1600 /*expected=*/{ref_bytes.get(), ref_size}));
1601 }
andrew@webrtc.orga8b97372014-03-10 22:26:121602 ref_size = ReadMessageBytesFromFile(ref_file, &ref_bytes);
1603 out_size = ReadMessageBytesFromFile(out_file, &out_bytes);
ivocd66b44d2016-01-15 11:06:361604 limited_size = ReadMessageBytesFromFile(limited_file, &limited_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:121605 }
1606 EXPECT_GT(bytes_read, 0u);
ivocd66b44d2016-01-15 11:06:361607 EXPECT_GT(bytes_read_limited, logging_expected_bytes);
1608 EXPECT_LE(bytes_read_limited, logging_limit_bytes);
andrew@webrtc.orga8b97372014-03-10 22:26:121609 EXPECT_NE(0, feof(ref_file));
1610 EXPECT_NE(0, feof(out_file));
ivocd66b44d2016-01-15 11:06:361611 EXPECT_NE(0, feof(limited_file));
andrew@webrtc.orga8b97372014-03-10 22:26:121612 ASSERT_EQ(0, fclose(ref_file));
1613 ASSERT_EQ(0, fclose(out_file));
ivocd66b44d2016-01-15 11:06:361614 ASSERT_EQ(0, fclose(limited_file));
Peter Boströmfade1792015-05-12 08:44:111615 remove(ref_filename.c_str());
1616 remove(out_filename.c_str());
ivocd66b44d2016-01-15 11:06:361617 remove(limited_filename.c_str());
andrew@webrtc.orga8b97372014-03-10 22:26:121618}
1619
pbosc7a65692016-05-06 19:50:041620TEST_F(ApmTest, VerifyDebugDumpInt) {
andrew@webrtc.orga8b97372014-03-10 22:26:121621 VerifyDebugDumpTest(kIntFormat);
1622}
1623
pbosc7a65692016-05-06 19:50:041624TEST_F(ApmTest, VerifyDebugDumpFloat) {
andrew@webrtc.orga8b97372014-03-10 22:26:121625 VerifyDebugDumpTest(kFloatFormat);
1626}
1627#endif
1628
andrew@webrtc.org7bf26462011-12-03 00:03:311629// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 19:50:041630TEST_F(ApmTest, DebugDump) {
Danil Chapovalov07122bc2019-03-26 13:37:011631 TaskQueueForTest worker_queue("ApmTest_worker_queue");
pbos@webrtc.orga525c982015-01-12 17:31:181632 const std::string filename =
1633 test::TempFilename(test::OutputPath(), "debug_aec");
aleloif4dd1912017-06-15 08:55:381634 {
Danil Chapovalovb64eef12024-01-04 13:45:231635 auto aec_dump = AecDumpFactory::Create("", -1, worker_queue.Get());
aleloif4dd1912017-06-15 08:55:381636 EXPECT_FALSE(aec_dump);
1637 }
andrew@webrtc.org7bf26462011-12-03 00:03:311638
1639#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1640 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 08:55:381641 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:311642
Danil Chapovalovb64eef12024-01-04 13:45:231643 auto aec_dump = AecDumpFactory::Create(filename, -1, worker_queue.Get());
aleloif4dd1912017-06-15 08:55:381644 EXPECT_TRUE(aec_dump);
1645 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 11:33:291646 EXPECT_EQ(apm_->kNoError,
1647 apm_->ProcessStream(
1648 frame_.data.data(),
1649 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1650 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581651 frame_.data.data()));
Per Åhgren2507f8c2020-03-19 11:33:291652 EXPECT_EQ(apm_->kNoError,
1653 apm_->ProcessReverseStream(
1654 revframe_.data.data(),
1655 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1656 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1657 revframe_.data.data()));
aleloif4dd1912017-06-15 08:55:381658 apm_->DetachAecDump();
andrew@webrtc.org7bf26462011-12-03 00:03:311659
1660 // Verify the file has been written.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:391661 FILE* fid = fopen(filename.c_str(), "r");
1662 ASSERT_TRUE(fid != NULL);
1663
andrew@webrtc.org7bf26462011-12-03 00:03:311664 // Clean it up.
andrew@webrtc.orgf5d8c3b2012-01-24 21:35:391665 ASSERT_EQ(0, fclose(fid));
andrew@webrtc.org7bf26462011-12-03 00:03:311666 ASSERT_EQ(0, remove(filename.c_str()));
1667#else
andrew@webrtc.org7bf26462011-12-03 00:03:311668 // Verify the file has NOT been written.
1669 ASSERT_TRUE(fopen(filename.c_str(), "r") == NULL);
1670#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1671}
1672
henrikg@webrtc.org863b5362013-12-06 16:05:171673// TODO(andrew): expand test to verify output.
pbosc7a65692016-05-06 19:50:041674TEST_F(ApmTest, DebugDumpFromFileHandle) {
Danil Chapovalov07122bc2019-03-26 13:37:011675 TaskQueueForTest worker_queue("ApmTest_worker_queue");
aleloif4dd1912017-06-15 08:55:381676
pbos@webrtc.orga525c982015-01-12 17:31:181677 const std::string filename =
1678 test::TempFilename(test::OutputPath(), "debug_aec");
Ali Tofigh2ab914c2022-04-13 10:55:151679 FileWrapper f = FileWrapper::OpenWriteOnly(filename);
Niels Möllere8e4dc42019-06-11 12:04:161680 ASSERT_TRUE(f.is_open());
henrikg@webrtc.org863b5362013-12-06 16:05:171681
1682#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP
1683 // Stopping without having started should be OK.
aleloif4dd1912017-06-15 08:55:381684 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:171685
Danil Chapovalovb64eef12024-01-04 13:45:231686 auto aec_dump = AecDumpFactory::Create(std::move(f), -1, worker_queue.Get());
aleloif4dd1912017-06-15 08:55:381687 EXPECT_TRUE(aec_dump);
1688 apm_->AttachAecDump(std::move(aec_dump));
Per Åhgren2507f8c2020-03-19 11:33:291689 EXPECT_EQ(apm_->kNoError,
1690 apm_->ProcessReverseStream(
1691 revframe_.data.data(),
1692 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1693 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1694 revframe_.data.data()));
1695 EXPECT_EQ(apm_->kNoError,
1696 apm_->ProcessStream(
1697 frame_.data.data(),
1698 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1699 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581700 frame_.data.data()));
aleloif4dd1912017-06-15 08:55:381701 apm_->DetachAecDump();
henrikg@webrtc.org863b5362013-12-06 16:05:171702
1703 // Verify the file has been written.
Niels Möllere8e4dc42019-06-11 12:04:161704 FILE* fid = fopen(filename.c_str(), "r");
henrikg@webrtc.org863b5362013-12-06 16:05:171705 ASSERT_TRUE(fid != NULL);
1706
1707 // Clean it up.
1708 ASSERT_EQ(0, fclose(fid));
1709 ASSERT_EQ(0, remove(filename.c_str()));
henrikg@webrtc.org863b5362013-12-06 16:05:171710#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP
1711}
1712
andrew@webrtc.org75f19482012-02-09 17:16:181713// TODO(andrew): Add a test to process a few frames with different combinations
1714// of enabled components.
1715
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441716TEST_F(ApmTest, Process) {
andrew@webrtc.org755b04a2011-11-15 16:57:561717 GOOGLE_PROTOBUF_VERIFY_VERSION;
andrew@webrtc.org27c69802014-02-18 20:24:561718 audioproc::OutputData ref_data;
andrew@webrtc.org755b04a2011-11-15 16:57:561719
Sam Zackrisson6558fa52019-08-26 08:12:411720 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:121721 OpenFileAndReadMessage(ref_filename_, &ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:561722 } else {
Sam Zackrisson3bd444f2022-08-03 12:37:001723 const int kChannels[] = {1, 2};
andrew@webrtc.orgdaacee82012-02-07 00:01:041724 // Write the desired tests to the protobuf reference file.
pkasting25702cb2016-01-08 21:50:271725 for (size_t i = 0; i < arraysize(kChannels); i++) {
1726 for (size_t j = 0; j < arraysize(kChannels); j++) {
Sam Zackrisson3bd444f2022-08-03 12:37:001727 for (int sample_rate_hz : AudioProcessing::kNativeSampleRatesHz) {
andrew@webrtc.org27c69802014-02-18 20:24:561728 audioproc::Test* test = ref_data.add_test();
andrew@webrtc.org60730cf2014-01-07 17:45:091729 test->set_num_reverse_channels(kChannels[i]);
1730 test->set_num_input_channels(kChannels[j]);
1731 test->set_num_output_channels(kChannels[j]);
Sam Zackrisson3bd444f2022-08-03 12:37:001732 test->set_sample_rate(sample_rate_hz);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:531733 test->set_use_aec_extended_filter(false);
andrew@webrtc.org755b04a2011-11-15 16:57:561734 }
1735 }
1736 }
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:531737#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1738 // To test the extended filter mode.
1739 audioproc::Test* test = ref_data.add_test();
1740 test->set_num_reverse_channels(2);
1741 test->set_num_input_channels(2);
1742 test->set_num_output_channels(2);
1743 test->set_sample_rate(AudioProcessing::kSampleRate32kHz);
1744 test->set_use_aec_extended_filter(true);
1745#endif
andrew@webrtc.org755b04a2011-11-15 16:57:561746 }
1747
andrew@webrtc.orgdaacee82012-02-07 00:01:041748 for (int i = 0; i < ref_data.test_size(); i++) {
1749 printf("Running test %d of %d...\n", i + 1, ref_data.test_size());
andrew@webrtc.org755b04a2011-11-15 16:57:561750
andrew@webrtc.org27c69802014-02-18 20:24:561751 audioproc::Test* test = ref_data.mutable_test(i);
andrew@webrtc.org60730cf2014-01-07 17:45:091752 // TODO(ajm): We no longer allow different input and output channels. Skip
1753 // these tests for now, but they should be removed from the set.
1754 if (test->num_input_channels() != test->num_output_channels())
1755 continue;
1756
Sam Zackrisson03cb7e52021-12-06 14:40:041757 apm_ = AudioProcessingBuilderForTesting()
1758 .SetEchoDetector(CreateEchoDetector())
1759 .Create();
Per Åhgren0695df12020-01-13 13:43:131760 AudioProcessing::Config apm_config = apm_->GetConfig();
1761 apm_config.gain_controller1.analog_gain_controller.enabled = false;
1762 apm_->ApplyConfig(apm_config);
aluebs@webrtc.orgf17ee9c2015-01-29 00:03:531763
1764 EnableAllComponents();
1765
Jonas Olssona4d87372019-07-05 17:08:331766 Init(test->sample_rate(), test->sample_rate(), test->sample_rate(),
Peter Kasting69558702016-01-13 00:26:351767 static_cast<size_t>(test->num_input_channels()),
1768 static_cast<size_t>(test->num_output_channels()),
Jonas Olssona4d87372019-07-05 17:08:331769 static_cast<size_t>(test->num_reverse_channels()), true);
andrew@webrtc.orgdaacee82012-02-07 00:01:041770
andrew@webrtc.org755b04a2011-11-15 16:57:561771 int frame_count = 0;
andrew@webrtc.org755b04a2011-11-15 16:57:561772 int analog_level = 127;
1773 int analog_level_average = 0;
1774 int max_output_average = 0;
minyue58530ed2016-05-24 12:50:121775#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Jonas Olssona4d87372019-07-05 17:08:331776 int stats_index = 0;
minyue58530ed2016-05-24 12:50:121777#endif
andrew@webrtc.org755b04a2011-11-15 16:57:561778
Sam Zackrisson70770ac2019-10-25 08:56:531779 while (ReadFrame(far_file_, &revframe_) && ReadFrame(near_file_, &frame_)) {
Per Åhgren2507f8c2020-03-19 11:33:291780 EXPECT_EQ(
1781 apm_->kNoError,
1782 apm_->ProcessReverseStream(
1783 revframe_.data.data(),
1784 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1785 StreamConfig(revframe_.sample_rate_hz, revframe_.num_channels),
1786 revframe_.data.data()));
andrew@webrtc.org755b04a2011-11-15 16:57:561787
1788 EXPECT_EQ(apm_->kNoError, apm_->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 08:10:261789 apm_->set_stream_analog_level(analog_level);
andrew@webrtc.org755b04a2011-11-15 16:57:561790
Per Åhgren2507f8c2020-03-19 11:33:291791 EXPECT_EQ(apm_->kNoError,
1792 apm_->ProcessStream(
1793 frame_.data.data(),
1794 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
1795 StreamConfig(frame_.sample_rate_hz, frame_.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:581796 frame_.data.data()));
andrew@webrtc.org17e40642014-03-04 20:58:131797
andrew@webrtc.orgdaacee82012-02-07 00:01:041798 // Ensure the frame was downmixed properly.
Peter Kasting69558702016-01-13 00:26:351799 EXPECT_EQ(static_cast<size_t>(test->num_output_channels()),
Per Åhgren2507f8c2020-03-19 11:33:291800 frame_.num_channels);
andrew@webrtc.org755b04a2011-11-15 16:57:561801
Sam Zackrisson70770ac2019-10-25 08:56:531802 max_output_average += MaxAudioFrame(frame_);
andrew@webrtc.org755b04a2011-11-15 16:57:561803
Sam Zackrisson41478c72019-10-15 08:10:261804 analog_level = apm_->recommended_stream_analog_level();
andrew@webrtc.org755b04a2011-11-15 16:57:561805 analog_level_average += analog_level;
Per Åhgrencf4c8722019-12-30 13:32:141806 AudioProcessingStats stats = apm_->GetStatistics();
bjornv@webrtc.org08329f42012-07-12 21:00:431807
Per Åhgren2507f8c2020-03-19 11:33:291808 size_t frame_size = frame_.samples_per_channel * frame_.num_channels;
Jonas Olssona4d87372019-07-05 17:08:331809 size_t write_count =
Per Åhgren2507f8c2020-03-19 11:33:291810 fwrite(frame_.data.data(), sizeof(int16_t), frame_size, out_file_);
andrew@webrtc.orgdaacee82012-02-07 00:01:041811 ASSERT_EQ(frame_size, write_count);
1812
1813 // Reset in case of downmixing.
Per Åhgren2507f8c2020-03-19 11:33:291814 frame_.num_channels = static_cast<size_t>(test->num_input_channels());
andrew@webrtc.org755b04a2011-11-15 16:57:561815 frame_count++;
minyue58530ed2016-05-24 12:50:121816
1817#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
1818 const int kStatsAggregationFrameNum = 100; // 1 second.
1819 if (frame_count % kStatsAggregationFrameNum == 0) {
Sam Zackrissonaf6c1392018-09-13 10:59:091820 // Get echo and delay metrics.
Mirko Bonadei54c90f22021-10-03 09:26:111821 AudioProcessingStats stats2 = apm_->GetStatistics();
minyue58530ed2016-05-24 12:50:121822
Sam Zackrissonaf6c1392018-09-13 10:59:091823 // Echo metrics.
Mirko Bonadei54c90f22021-10-03 09:26:111824 const float echo_return_loss = stats2.echo_return_loss.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 10:59:091825 const float echo_return_loss_enhancement =
Mirko Bonadei54c90f22021-10-03 09:26:111826 stats2.echo_return_loss_enhancement.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 10:59:091827 const float residual_echo_likelihood =
Mirko Bonadei54c90f22021-10-03 09:26:111828 stats2.residual_echo_likelihood.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 10:59:091829 const float residual_echo_likelihood_recent_max =
Mirko Bonadei54c90f22021-10-03 09:26:111830 stats2.residual_echo_likelihood_recent_max.value_or(-1.0f);
Sam Zackrissonaf6c1392018-09-13 10:59:091831
Sam Zackrisson6558fa52019-08-26 08:12:411832 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
minyue58530ed2016-05-24 12:50:121833 const audioproc::Test::EchoMetrics& reference =
1834 test->echo_metrics(stats_index);
Sam Zackrissonaf6c1392018-09-13 10:59:091835 constexpr float kEpsilon = 0.01;
1836 EXPECT_NEAR(echo_return_loss, reference.echo_return_loss(), kEpsilon);
1837 EXPECT_NEAR(echo_return_loss_enhancement,
1838 reference.echo_return_loss_enhancement(), kEpsilon);
Sam Zackrissonaf6c1392018-09-13 10:59:091839 EXPECT_NEAR(residual_echo_likelihood,
1840 reference.residual_echo_likelihood(), kEpsilon);
1841 EXPECT_NEAR(residual_echo_likelihood_recent_max,
1842 reference.residual_echo_likelihood_recent_max(),
1843 kEpsilon);
minyue58530ed2016-05-24 12:50:121844 ++stats_index;
1845 } else {
Sam Zackrissonaf6c1392018-09-13 10:59:091846 audioproc::Test::EchoMetrics* message_echo = test->add_echo_metrics();
1847 message_echo->set_echo_return_loss(echo_return_loss);
1848 message_echo->set_echo_return_loss_enhancement(
1849 echo_return_loss_enhancement);
Sam Zackrissonaf6c1392018-09-13 10:59:091850 message_echo->set_residual_echo_likelihood(residual_echo_likelihood);
1851 message_echo->set_residual_echo_likelihood_recent_max(
1852 residual_echo_likelihood_recent_max);
minyue58530ed2016-05-24 12:50:121853 }
1854 }
1855#endif // defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE).
andrew@webrtc.org755b04a2011-11-15 16:57:561856 }
1857 max_output_average /= frame_count;
1858 analog_level_average /= frame_count;
1859
Sam Zackrisson6558fa52019-08-26 08:12:411860 if (!absl::GetFlag(FLAGS_write_apm_ref_data)) {
bjornv@webrtc.org8dd60cc2014-09-11 08:36:351861 const int kIntNear = 1;
Alessio Bazzica1db0a262022-02-15 14:18:091862 // All numbers being consistently higher on N7 compare to the reference
1863 // data.
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441864 // TODO(bjornv): If we start getting more of these offsets on Android we
1865 // should consider a different approach. Either using one slack for all,
1866 // or generate a separate android reference.
Kári Tristan Helgason640106e2018-09-06 13:29:451867#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441868 const int kMaxOutputAverageOffset = 9;
Sam Zackrissone507b0c2018-07-20 13:22:501869 const int kMaxOutputAverageNear = 26;
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441870#else
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441871 const int kMaxOutputAverageOffset = 0;
1872 const int kMaxOutputAverageNear = kIntNear;
1873#endif
bjornv@webrtc.org8dd60cc2014-09-11 08:36:351874 EXPECT_NEAR(test->analog_level_average(), analog_level_average, kIntNear);
bjornv@webrtc.orgdc0b37d2014-09-23 05:03:441875 EXPECT_NEAR(test->max_output_average(),
1876 max_output_average - kMaxOutputAverageOffset,
1877 kMaxOutputAverageNear);
andrew@webrtc.org755b04a2011-11-15 16:57:561878 } else {
andrew@webrtc.org755b04a2011-11-15 16:57:561879 test->set_analog_level_average(analog_level_average);
1880 test->set_max_output_average(max_output_average);
andrew@webrtc.org755b04a2011-11-15 16:57:561881 }
1882
1883 rewind(far_file_);
1884 rewind(near_file_);
1885 }
1886
Sam Zackrisson6558fa52019-08-26 08:12:411887 if (absl::GetFlag(FLAGS_write_apm_ref_data)) {
andrew@webrtc.orga8b97372014-03-10 22:26:121888 OpenFileAndWriteMessage(ref_filename_, ref_data);
andrew@webrtc.org755b04a2011-11-15 16:57:561889 }
1890}
andrew@webrtc.orgddbb8a22014-04-22 21:00:041891
andrew@webrtc.orgddbb8a22014-04-22 21:00:041892// Compares the reference and test arrays over a region around the expected
1893// delay. Finds the highest SNR in that region and adds the variance and squared
1894// error results to the supplied accumulators.
1895void UpdateBestSNR(const float* ref,
1896 const float* test,
pkasting25702cb2016-01-08 21:50:271897 size_t length,
andrew@webrtc.orgddbb8a22014-04-22 21:00:041898 int expected_delay,
1899 double* variance_acc,
1900 double* sq_error_acc) {
Sam Zackrisson3bd444f2022-08-03 12:37:001901 RTC_CHECK_LT(expected_delay, length)
1902 << "delay greater than signal length, cannot compute SNR";
andrew@webrtc.orgddbb8a22014-04-22 21:00:041903 double best_snr = std::numeric_limits<double>::min();
1904 double best_variance = 0;
1905 double best_sq_error = 0;
Sam Zackrisson3bd444f2022-08-03 12:37:001906 // Search over a region of nine samples around the expected delay.
andrew@webrtc.orgddbb8a22014-04-22 21:00:041907 for (int delay = std::max(expected_delay - 4, 0); delay <= expected_delay + 4;
1908 ++delay) {
1909 double sq_error = 0;
1910 double variance = 0;
pkasting25702cb2016-01-08 21:50:271911 for (size_t i = 0; i < length - delay; ++i) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041912 double error = test[i + delay] - ref[i];
1913 sq_error += error * error;
1914 variance += ref[i] * ref[i];
1915 }
1916
1917 if (sq_error == 0) {
1918 *variance_acc += variance;
1919 return;
1920 }
1921 double snr = variance / sq_error;
1922 if (snr > best_snr) {
1923 best_snr = snr;
1924 best_variance = variance;
1925 best_sq_error = sq_error;
1926 }
1927 }
1928
1929 *variance_acc += best_variance;
1930 *sq_error_acc += best_sq_error;
1931}
1932
1933// Used to test a multitude of sample rate and channel combinations. It works
1934// by first producing a set of reference files (in SetUpTestCase) that are
1935// assumed to be correct, as the used parameters are verified by other tests
1936// in this collection. Primarily the reference files are all produced at
1937// "native" rates which do not involve any resampling.
1938
1939// Each test pass produces an output file with a particular format. The output
1940// is matched against the reference file closest to its internal processing
1941// format. If necessary the output is resampled back to its process format.
1942// Due to the resampling distortion, we don't expect identical results, but
1943// enforce SNR thresholds which vary depending on the format. 0 is a special
1944// case SNR which corresponds to inf, or zero error.
Edward Lemurc5ee9872017-10-23 21:33:041945typedef std::tuple<int, int, int, int, double, double> AudioProcessingTestData;
andrew@webrtc.orgddbb8a22014-04-22 21:00:041946class AudioProcessingTest
Mirko Bonadei6a489f22019-04-09 13:11:121947 : public ::testing::TestWithParam<AudioProcessingTestData> {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041948 public:
1949 AudioProcessingTest()
Edward Lemurc5ee9872017-10-23 21:33:041950 : input_rate_(std::get<0>(GetParam())),
1951 output_rate_(std::get<1>(GetParam())),
1952 reverse_input_rate_(std::get<2>(GetParam())),
1953 reverse_output_rate_(std::get<3>(GetParam())),
1954 expected_snr_(std::get<4>(GetParam())),
1955 expected_reverse_snr_(std::get<5>(GetParam())) {}
andrew@webrtc.orgddbb8a22014-04-22 21:00:041956
1957 virtual ~AudioProcessingTest() {}
1958
Mirko Bonadei71061bc2019-06-04 07:01:511959 static void SetUpTestSuite() {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041960 // Create all needed output reference files.
Peter Kasting69558702016-01-13 00:26:351961 const size_t kNumChannels[] = {1, 2};
Sam Zackrisson3bd444f2022-08-03 12:37:001962 for (size_t i = 0; i < arraysize(kProcessSampleRates); ++i) {
pkasting25702cb2016-01-08 21:50:271963 for (size_t j = 0; j < arraysize(kNumChannels); ++j) {
1964 for (size_t k = 0; k < arraysize(kNumChannels); ++k) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:041965 // The reference files always have matching input and output channels.
Sam Zackrisson3bd444f2022-08-03 12:37:001966 ProcessFormat(kProcessSampleRates[i], kProcessSampleRates[i],
1967 kProcessSampleRates[i], kProcessSampleRates[i],
1968 kNumChannels[j], kNumChannels[j], kNumChannels[k],
1969 kNumChannels[k], "ref");
andrew@webrtc.orgddbb8a22014-04-22 21:00:041970 }
1971 }
1972 }
1973 }
1974
Gustaf Ullberg8ffeeb22017-10-11 09:42:381975 void TearDown() {
1976 // Remove "out" files after each test.
1977 ClearTempOutFiles();
1978 }
1979
Mirko Bonadei71061bc2019-06-04 07:01:511980 static void TearDownTestSuite() { ClearTempFiles(); }
ekmeyerson60d9b332015-08-14 17:35:551981
andrew@webrtc.orgddbb8a22014-04-22 21:00:041982 // Runs a process pass on files with the given parameters and dumps the output
Artem Titov0b489302021-07-28 18:50:031983 // to a file specified with `output_file_prefix`. Both forward and reverse
ekmeyerson60d9b332015-08-14 17:35:551984 // output streams are dumped.
andrew@webrtc.orgddbb8a22014-04-22 21:00:041985 static void ProcessFormat(int input_rate,
1986 int output_rate,
ekmeyerson60d9b332015-08-14 17:35:551987 int reverse_input_rate,
1988 int reverse_output_rate,
Peter Kasting69558702016-01-13 00:26:351989 size_t num_input_channels,
1990 size_t num_output_channels,
1991 size_t num_reverse_input_channels,
1992 size_t num_reverse_output_channels,
Ali Tofighf3592cb2022-08-16 12:44:381993 absl::string_view output_file_prefix) {
Sam Zackrisson3bd444f2022-08-03 12:37:001994 AudioProcessing::Config apm_config;
Per Åhgren0695df12020-01-13 13:43:131995 apm_config.gain_controller1.analog_gain_controller.enabled = false;
Sam Zackrisson3bd444f2022-08-03 12:37:001996 rtc::scoped_refptr<AudioProcessing> ap =
1997 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren0695df12020-01-13 13:43:131998
andrew@webrtc.orgddbb8a22014-04-22 21:00:041999 EnableAllAPComponents(ap.get());
andrew@webrtc.orgddbb8a22014-04-22 21:00:042000
ekmeyerson60d9b332015-08-14 17:35:552001 ProcessingConfig processing_config = {
2002 {{input_rate, num_input_channels},
2003 {output_rate, num_output_channels},
2004 {reverse_input_rate, num_reverse_input_channels},
2005 {reverse_output_rate, num_reverse_output_channels}}};
2006 ap->Initialize(processing_config);
2007
2008 FILE* far_file =
2009 fopen(ResourceFilePath("far", reverse_input_rate).c_str(), "rb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:042010 FILE* near_file = fopen(ResourceFilePath("near", input_rate).c_str(), "rb");
Jonas Olssona4d87372019-07-05 17:08:332011 FILE* out_file = fopen(
2012 OutputFilePath(
2013 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2014 reverse_output_rate, num_input_channels, num_output_channels,
2015 num_reverse_input_channels, num_reverse_output_channels, kForward)
2016 .c_str(),
2017 "wb");
2018 FILE* rev_out_file = fopen(
2019 OutputFilePath(
2020 output_file_prefix, input_rate, output_rate, reverse_input_rate,
2021 reverse_output_rate, num_input_channels, num_output_channels,
2022 num_reverse_input_channels, num_reverse_output_channels, kReverse)
2023 .c_str(),
2024 "wb");
andrew@webrtc.orgddbb8a22014-04-22 21:00:042025 ASSERT_TRUE(far_file != NULL);
2026 ASSERT_TRUE(near_file != NULL);
2027 ASSERT_TRUE(out_file != NULL);
ekmeyerson60d9b332015-08-14 17:35:552028 ASSERT_TRUE(rev_out_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042029
Sam Zackrisson3bd444f2022-08-03 12:37:002030 ChannelBuffer<float> fwd_cb(AudioProcessing::GetFrameSize(input_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042031 num_input_channels);
Sam Zackrisson3bd444f2022-08-03 12:37:002032 ChannelBuffer<float> rev_cb(
2033 AudioProcessing::GetFrameSize(reverse_input_rate),
2034 num_reverse_input_channels);
2035 ChannelBuffer<float> out_cb(AudioProcessing::GetFrameSize(output_rate),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042036 num_output_channels);
Sam Zackrisson3bd444f2022-08-03 12:37:002037 ChannelBuffer<float> rev_out_cb(
2038 AudioProcessing::GetFrameSize(reverse_output_rate),
2039 num_reverse_output_channels);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042040
2041 // Temporary buffers.
2042 const int max_length =
ekmeyerson60d9b332015-08-14 17:35:552043 2 * std::max(std::max(out_cb.num_frames(), rev_out_cb.num_frames()),
2044 std::max(fwd_cb.num_frames(), rev_cb.num_frames()));
kwiberg62eaacf2016-02-17 14:39:052045 std::unique_ptr<float[]> float_data(new float[max_length]);
2046 std::unique_ptr<int16_t[]> int_data(new int16_t[max_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042047
2048 int analog_level = 127;
2049 while (ReadChunk(far_file, int_data.get(), float_data.get(), &rev_cb) &&
2050 ReadChunk(near_file, int_data.get(), float_data.get(), &fwd_cb)) {
ekmeyerson60d9b332015-08-14 17:35:552051 EXPECT_NOERR(ap->ProcessReverseStream(
2052 rev_cb.channels(), processing_config.reverse_input_stream(),
2053 processing_config.reverse_output_stream(), rev_out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:042054
2055 EXPECT_NOERR(ap->set_stream_delay_ms(0));
Sam Zackrisson41478c72019-10-15 08:10:262056 ap->set_stream_analog_level(analog_level);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042057
2058 EXPECT_NOERR(ap->ProcessStream(
Gustaf Ullbergcb307262019-10-29 08:30:442059 fwd_cb.channels(), StreamConfig(input_rate, num_input_channels),
2060 StreamConfig(output_rate, num_output_channels), out_cb.channels()));
andrew@webrtc.orgddbb8a22014-04-22 21:00:042061
ekmeyerson60d9b332015-08-14 17:35:552062 // Dump forward output to file.
2063 Interleave(out_cb.channels(), out_cb.num_frames(), out_cb.num_channels(),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042064 float_data.get());
pkasting25702cb2016-01-08 21:50:272065 size_t out_length = out_cb.num_channels() * out_cb.num_frames();
ekmeyerson60d9b332015-08-14 17:35:552066
Jonas Olssona4d87372019-07-05 17:08:332067 ASSERT_EQ(out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2068 out_length, out_file));
andrew@webrtc.orgddbb8a22014-04-22 21:00:042069
ekmeyerson60d9b332015-08-14 17:35:552070 // Dump reverse output to file.
2071 Interleave(rev_out_cb.channels(), rev_out_cb.num_frames(),
2072 rev_out_cb.num_channels(), float_data.get());
pkasting25702cb2016-01-08 21:50:272073 size_t rev_out_length =
2074 rev_out_cb.num_channels() * rev_out_cb.num_frames();
ekmeyerson60d9b332015-08-14 17:35:552075
Jonas Olssona4d87372019-07-05 17:08:332076 ASSERT_EQ(rev_out_length, fwrite(float_data.get(), sizeof(float_data[0]),
2077 rev_out_length, rev_out_file));
ekmeyerson60d9b332015-08-14 17:35:552078
Sam Zackrisson41478c72019-10-15 08:10:262079 analog_level = ap->recommended_stream_analog_level();
andrew@webrtc.orgddbb8a22014-04-22 21:00:042080 }
2081 fclose(far_file);
2082 fclose(near_file);
2083 fclose(out_file);
ekmeyerson60d9b332015-08-14 17:35:552084 fclose(rev_out_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042085 }
2086
2087 protected:
2088 int input_rate_;
2089 int output_rate_;
ekmeyerson60d9b332015-08-14 17:35:552090 int reverse_input_rate_;
2091 int reverse_output_rate_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:042092 double expected_snr_;
ekmeyerson60d9b332015-08-14 17:35:552093 double expected_reverse_snr_;
andrew@webrtc.orgddbb8a22014-04-22 21:00:042094};
2095
bjornv@webrtc.org2812b592014-06-02 11:27:292096TEST_P(AudioProcessingTest, Formats) {
andrew@webrtc.orgddbb8a22014-04-22 21:00:042097 struct ChannelFormat {
2098 int num_input;
2099 int num_output;
ekmeyerson60d9b332015-08-14 17:35:552100 int num_reverse_input;
2101 int num_reverse_output;
andrew@webrtc.orgddbb8a22014-04-22 21:00:042102 };
2103 ChannelFormat cf[] = {
Jonas Olssona4d87372019-07-05 17:08:332104 {1, 1, 1, 1}, {1, 1, 2, 1}, {2, 1, 1, 1},
2105 {2, 1, 2, 1}, {2, 2, 1, 1}, {2, 2, 2, 2},
andrew@webrtc.orgddbb8a22014-04-22 21:00:042106 };
andrew@webrtc.orgddbb8a22014-04-22 21:00:042107
pkasting25702cb2016-01-08 21:50:272108 for (size_t i = 0; i < arraysize(cf); ++i) {
ekmeyerson60d9b332015-08-14 17:35:552109 ProcessFormat(input_rate_, output_rate_, reverse_input_rate_,
2110 reverse_output_rate_, cf[i].num_input, cf[i].num_output,
2111 cf[i].num_reverse_input, cf[i].num_reverse_output, "out");
Alejandro Luebs47748742015-05-22 19:00:212112
ekmeyerson60d9b332015-08-14 17:35:552113 // Verify output for both directions.
2114 std::vector<StreamDirection> stream_directions;
2115 stream_directions.push_back(kForward);
2116 stream_directions.push_back(kReverse);
2117 for (StreamDirection file_direction : stream_directions) {
2118 const int in_rate = file_direction ? reverse_input_rate_ : input_rate_;
2119 const int out_rate = file_direction ? reverse_output_rate_ : output_rate_;
2120 const int out_num =
2121 file_direction ? cf[i].num_reverse_output : cf[i].num_output;
2122 const double expected_snr =
2123 file_direction ? expected_reverse_snr_ : expected_snr_;
2124
2125 const int min_ref_rate = std::min(in_rate, out_rate);
2126 int ref_rate;
ekmeyerson60d9b332015-08-14 17:35:552127 if (min_ref_rate > 32000) {
2128 ref_rate = 48000;
2129 } else if (min_ref_rate > 16000) {
2130 ref_rate = 32000;
ekmeyerson60d9b332015-08-14 17:35:552131 } else {
Sam Zackrisson3bd444f2022-08-03 12:37:002132 ref_rate = 16000;
ekmeyerson60d9b332015-08-14 17:35:552133 }
Per Åhgrenc0424252019-12-10 12:04:152134
ekmeyerson60d9b332015-08-14 17:35:552135 FILE* out_file = fopen(
2136 OutputFilePath("out", input_rate_, output_rate_, reverse_input_rate_,
2137 reverse_output_rate_, cf[i].num_input,
2138 cf[i].num_output, cf[i].num_reverse_input,
Jonas Olssona4d87372019-07-05 17:08:332139 cf[i].num_reverse_output, file_direction)
2140 .c_str(),
ekmeyerson60d9b332015-08-14 17:35:552141 "rb");
2142 // The reference files always have matching input and output channels.
Jonas Olssona4d87372019-07-05 17:08:332143 FILE* ref_file =
2144 fopen(OutputFilePath("ref", ref_rate, ref_rate, ref_rate, ref_rate,
2145 cf[i].num_output, cf[i].num_output,
2146 cf[i].num_reverse_output,
2147 cf[i].num_reverse_output, file_direction)
2148 .c_str(),
2149 "rb");
ekmeyerson60d9b332015-08-14 17:35:552150 ASSERT_TRUE(out_file != NULL);
2151 ASSERT_TRUE(ref_file != NULL);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042152
Sam Zackrisson3bd444f2022-08-03 12:37:002153 const size_t ref_length =
2154 AudioProcessing::GetFrameSize(ref_rate) * out_num;
2155 const size_t out_length =
2156 AudioProcessing::GetFrameSize(out_rate) * out_num;
ekmeyerson60d9b332015-08-14 17:35:552157 // Data from the reference file.
kwiberg62eaacf2016-02-17 14:39:052158 std::unique_ptr<float[]> ref_data(new float[ref_length]);
ekmeyerson60d9b332015-08-14 17:35:552159 // Data from the output file.
kwiberg62eaacf2016-02-17 14:39:052160 std::unique_ptr<float[]> out_data(new float[out_length]);
ekmeyerson60d9b332015-08-14 17:35:552161 // Data from the resampled output, in case the reference and output rates
2162 // don't match.
kwiberg62eaacf2016-02-17 14:39:052163 std::unique_ptr<float[]> cmp_data(new float[ref_length]);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042164
ekmeyerson60d9b332015-08-14 17:35:552165 PushResampler<float> resampler;
2166 resampler.InitializeIfNeeded(out_rate, ref_rate, out_num);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042167
ekmeyerson60d9b332015-08-14 17:35:552168 // Compute the resampling delay of the output relative to the reference,
2169 // to find the region over which we should search for the best SNR.
2170 float expected_delay_sec = 0;
2171 if (in_rate != ref_rate) {
2172 // Input resampling delay.
2173 expected_delay_sec +=
2174 PushSincResampler::AlgorithmicDelaySeconds(in_rate);
2175 }
2176 if (out_rate != ref_rate) {
2177 // Output resampling delay.
2178 expected_delay_sec +=
2179 PushSincResampler::AlgorithmicDelaySeconds(ref_rate);
2180 // Delay of converting the output back to its processing rate for
2181 // testing.
2182 expected_delay_sec +=
2183 PushSincResampler::AlgorithmicDelaySeconds(out_rate);
2184 }
Sam Zackrisson3bd444f2022-08-03 12:37:002185 // The delay is multiplied by the number of channels because
2186 // UpdateBestSNR() computes the SNR over interleaved data without taking
2187 // channels into account.
ekmeyerson60d9b332015-08-14 17:35:552188 int expected_delay =
Oleh Prypin708eccc2019-03-27 08:38:522189 std::floor(expected_delay_sec * ref_rate + 0.5f) * out_num;
andrew@webrtc.orgddbb8a22014-04-22 21:00:042190
ekmeyerson60d9b332015-08-14 17:35:552191 double variance = 0;
2192 double sq_error = 0;
2193 while (fread(out_data.get(), sizeof(out_data[0]), out_length, out_file) &&
2194 fread(ref_data.get(), sizeof(ref_data[0]), ref_length, ref_file)) {
2195 float* out_ptr = out_data.get();
2196 if (out_rate != ref_rate) {
2197 // Resample the output back to its internal processing rate if
Sam Zackrisson3bd444f2022-08-03 12:37:002198 // necessary.
pkasting25702cb2016-01-08 21:50:272199 ASSERT_EQ(ref_length,
2200 static_cast<size_t>(resampler.Resample(
2201 out_ptr, out_length, cmp_data.get(), ref_length)));
ekmeyerson60d9b332015-08-14 17:35:552202 out_ptr = cmp_data.get();
2203 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:042204
Artem Titov0b489302021-07-28 18:50:032205 // Update the `sq_error` and `variance` accumulators with the highest
ekmeyerson60d9b332015-08-14 17:35:552206 // SNR of reference vs output.
2207 UpdateBestSNR(ref_data.get(), out_ptr, ref_length, expected_delay,
2208 &variance, &sq_error);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042209 }
2210
ekmeyerson60d9b332015-08-14 17:35:552211 std::cout << "(" << input_rate_ << ", " << output_rate_ << ", "
2212 << reverse_input_rate_ << ", " << reverse_output_rate_ << ", "
2213 << cf[i].num_input << ", " << cf[i].num_output << ", "
2214 << cf[i].num_reverse_input << ", " << cf[i].num_reverse_output
2215 << ", " << file_direction << "): ";
2216 if (sq_error > 0) {
2217 double snr = 10 * log10(variance / sq_error);
2218 EXPECT_GE(snr, expected_snr);
2219 EXPECT_NE(0, expected_snr);
2220 std::cout << "SNR=" << snr << " dB" << std::endl;
2221 } else {
aluebs776593b2016-03-15 21:04:582222 std::cout << "SNR=inf dB" << std::endl;
ekmeyerson60d9b332015-08-14 17:35:552223 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:042224
ekmeyerson60d9b332015-08-14 17:35:552225 fclose(out_file);
2226 fclose(ref_file);
andrew@webrtc.orgddbb8a22014-04-22 21:00:042227 }
andrew@webrtc.orgddbb8a22014-04-22 21:00:042228 }
2229}
2230
2231#if defined(WEBRTC_AUDIOPROC_FLOAT_PROFILE)
Mirko Bonadeic84f6612019-01-31 11:20:572232INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 17:35:552233 CommonFormats,
2234 AudioProcessingTest,
Sam Zackrisson3bd444f2022-08-03 12:37:002235 // Internal processing rates and the particularly common sample rate 44100
2236 // Hz are tested in a grid of combinations (capture in, render in, out).
Mirko Bonadei6a489f22019-04-09 13:11:122237 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 0, 0),
2238 std::make_tuple(48000, 48000, 32000, 48000, 40, 30),
2239 std::make_tuple(48000, 48000, 16000, 48000, 40, 20),
2240 std::make_tuple(48000, 44100, 48000, 44100, 20, 20),
2241 std::make_tuple(48000, 44100, 32000, 44100, 20, 15),
2242 std::make_tuple(48000, 44100, 16000, 44100, 20, 15),
2243 std::make_tuple(48000, 32000, 48000, 32000, 30, 35),
2244 std::make_tuple(48000, 32000, 32000, 32000, 30, 0),
2245 std::make_tuple(48000, 32000, 16000, 32000, 30, 20),
2246 std::make_tuple(48000, 16000, 48000, 16000, 25, 20),
2247 std::make_tuple(48000, 16000, 32000, 16000, 25, 20),
2248 std::make_tuple(48000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 19:00:212249
Mirko Bonadei6a489f22019-04-09 13:11:122250 std::make_tuple(44100, 48000, 48000, 48000, 30, 0),
2251 std::make_tuple(44100, 48000, 32000, 48000, 30, 30),
2252 std::make_tuple(44100, 48000, 16000, 48000, 30, 20),
2253 std::make_tuple(44100, 44100, 48000, 44100, 20, 20),
2254 std::make_tuple(44100, 44100, 32000, 44100, 20, 15),
2255 std::make_tuple(44100, 44100, 16000, 44100, 20, 15),
2256 std::make_tuple(44100, 32000, 48000, 32000, 30, 35),
2257 std::make_tuple(44100, 32000, 32000, 32000, 30, 0),
2258 std::make_tuple(44100, 32000, 16000, 32000, 30, 20),
2259 std::make_tuple(44100, 16000, 48000, 16000, 25, 20),
2260 std::make_tuple(44100, 16000, 32000, 16000, 25, 20),
2261 std::make_tuple(44100, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 19:00:212262
Per Åhgrenc0424252019-12-10 12:04:152263 std::make_tuple(32000, 48000, 48000, 48000, 15, 0),
2264 std::make_tuple(32000, 48000, 32000, 48000, 15, 30),
2265 std::make_tuple(32000, 48000, 16000, 48000, 15, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122266 std::make_tuple(32000, 44100, 48000, 44100, 19, 20),
2267 std::make_tuple(32000, 44100, 32000, 44100, 19, 15),
2268 std::make_tuple(32000, 44100, 16000, 44100, 19, 15),
2269 std::make_tuple(32000, 32000, 48000, 32000, 40, 35),
2270 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Gustaf Ullberg09226fc2021-02-19 12:03:142271 std::make_tuple(32000, 32000, 16000, 32000, 39, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122272 std::make_tuple(32000, 16000, 48000, 16000, 25, 20),
2273 std::make_tuple(32000, 16000, 32000, 16000, 25, 20),
2274 std::make_tuple(32000, 16000, 16000, 16000, 25, 0),
Alejandro Luebs47748742015-05-22 19:00:212275
Per Åhgrenc0424252019-12-10 12:04:152276 std::make_tuple(16000, 48000, 48000, 48000, 9, 0),
2277 std::make_tuple(16000, 48000, 32000, 48000, 9, 30),
2278 std::make_tuple(16000, 48000, 16000, 48000, 9, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122279 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2280 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2281 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
2282 std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
2283 std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
2284 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
2285 std::make_tuple(16000, 16000, 48000, 16000, 39, 20),
Gustaf Ullberg09226fc2021-02-19 12:03:142286 std::make_tuple(16000, 16000, 32000, 16000, 39, 20),
Sam Zackrisson3bd444f2022-08-03 12:37:002287 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2288
2289 // Other sample rates are not tested exhaustively, to keep
2290 // the test runtime manageable.
2291 //
2292 // Testing most other sample rates logged by Chrome UMA:
2293 // - WebRTC.AudioInputSampleRate
2294 // - WebRTC.AudioOutputSampleRate
2295 // ApmConfiguration.HandlingOfRateCombinations covers
2296 // remaining sample rates.
2297 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2298 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2299 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2300 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2301 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
Alejandro Luebs47748742015-05-22 19:00:212302
2303#elif defined(WEBRTC_AUDIOPROC_FIXED_PROFILE)
Mirko Bonadeic84f6612019-01-31 11:20:572304INSTANTIATE_TEST_SUITE_P(
ekmeyerson60d9b332015-08-14 17:35:552305 CommonFormats,
2306 AudioProcessingTest,
Per Åhgren0aefbf02019-08-23 19:29:172307 ::testing::Values(std::make_tuple(48000, 48000, 48000, 48000, 19, 0),
2308 std::make_tuple(48000, 48000, 32000, 48000, 19, 30),
2309 std::make_tuple(48000, 48000, 16000, 48000, 19, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122310 std::make_tuple(48000, 44100, 48000, 44100, 15, 20),
2311 std::make_tuple(48000, 44100, 32000, 44100, 15, 15),
2312 std::make_tuple(48000, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 19:29:172313 std::make_tuple(48000, 32000, 48000, 32000, 19, 35),
2314 std::make_tuple(48000, 32000, 32000, 32000, 19, 0),
2315 std::make_tuple(48000, 32000, 16000, 32000, 19, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122316 std::make_tuple(48000, 16000, 48000, 16000, 20, 20),
2317 std::make_tuple(48000, 16000, 32000, 16000, 20, 20),
2318 std::make_tuple(48000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042319
Mirko Bonadei6a489f22019-04-09 13:11:122320 std::make_tuple(44100, 48000, 48000, 48000, 15, 0),
2321 std::make_tuple(44100, 48000, 32000, 48000, 15, 30),
2322 std::make_tuple(44100, 48000, 16000, 48000, 15, 20),
2323 std::make_tuple(44100, 44100, 48000, 44100, 15, 20),
2324 std::make_tuple(44100, 44100, 32000, 44100, 15, 15),
2325 std::make_tuple(44100, 44100, 16000, 44100, 15, 15),
Per Åhgren0aefbf02019-08-23 19:29:172326 std::make_tuple(44100, 32000, 48000, 32000, 18, 35),
2327 std::make_tuple(44100, 32000, 32000, 32000, 18, 0),
2328 std::make_tuple(44100, 32000, 16000, 32000, 18, 20),
2329 std::make_tuple(44100, 16000, 48000, 16000, 19, 20),
2330 std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
2331 std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042332
Per Åhgrenc0424252019-12-10 12:04:152333 std::make_tuple(32000, 48000, 48000, 48000, 17, 0),
2334 std::make_tuple(32000, 48000, 32000, 48000, 17, 30),
2335 std::make_tuple(32000, 48000, 16000, 48000, 17, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122336 std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
2337 std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
2338 std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
Per Åhgrene35b32c2019-11-22 17:22:042339 std::make_tuple(32000, 32000, 48000, 32000, 27, 35),
Mirko Bonadei6a489f22019-04-09 13:11:122340 std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
Per Åhgrene35b32c2019-11-22 17:22:042341 std::make_tuple(32000, 32000, 16000, 32000, 30, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122342 std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
2343 std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
2344 std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
andrew@webrtc.orgddbb8a22014-04-22 21:00:042345
Per Åhgrenc0424252019-12-10 12:04:152346 std::make_tuple(16000, 48000, 48000, 48000, 11, 0),
2347 std::make_tuple(16000, 48000, 32000, 48000, 11, 30),
2348 std::make_tuple(16000, 48000, 16000, 48000, 11, 20),
Mirko Bonadei6a489f22019-04-09 13:11:122349 std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
2350 std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
2351 std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
Per Åhgren0cbb58e2019-10-29 21:59:442352 std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
Per Åhgrene35b32c2019-11-22 17:22:042353 std::make_tuple(16000, 32000, 32000, 32000, 24, 0),
Mirko Bonadei6a489f22019-04-09 13:11:122354 std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
Per Åhgrene35b32c2019-11-22 17:22:042355 std::make_tuple(16000, 16000, 48000, 16000, 28, 20),
2356 std::make_tuple(16000, 16000, 32000, 16000, 28, 20),
Sam Zackrisson3bd444f2022-08-03 12:37:002357 std::make_tuple(16000, 16000, 16000, 16000, 0, 0),
2358
2359 std::make_tuple(192000, 192000, 48000, 192000, 20, 40),
2360 std::make_tuple(176400, 176400, 48000, 176400, 20, 35),
2361 std::make_tuple(96000, 96000, 48000, 96000, 20, 40),
2362 std::make_tuple(88200, 88200, 48000, 88200, 20, 20),
2363 std::make_tuple(44100, 44100, 48000, 44100, 20, 20)));
andrew@webrtc.orgddbb8a22014-04-22 21:00:042364#endif
2365
Per Åhgren3e8bf282019-08-29 21:38:402366// Produces a scoped trace debug output.
2367std::string ProduceDebugText(int render_input_sample_rate_hz,
2368 int render_output_sample_rate_hz,
2369 int capture_input_sample_rate_hz,
2370 int capture_output_sample_rate_hz,
2371 size_t render_input_num_channels,
2372 size_t render_output_num_channels,
2373 size_t capture_input_num_channels,
2374 size_t capture_output_num_channels) {
2375 rtc::StringBuilder ss;
2376 ss << "Sample rates:"
Jonas Olsson6c9bc392020-01-14 14:54:352377 "\n Render input: "
Jonas Olssonb2b20312020-01-14 11:11:312378 << render_input_sample_rate_hz
2379 << " Hz"
Jonas Olsson6c9bc392020-01-14 14:54:352380 "\n Render output: "
Jonas Olssonb2b20312020-01-14 11:11:312381 << render_output_sample_rate_hz
2382 << " Hz"
Jonas Olsson6c9bc392020-01-14 14:54:352383 "\n Capture input: "
Jonas Olssonb2b20312020-01-14 11:11:312384 << capture_input_sample_rate_hz
2385 << " Hz"
Jonas Olsson6c9bc392020-01-14 14:54:352386 "\n Capture output: "
Jonas Olssonb2b20312020-01-14 11:11:312387 << capture_output_sample_rate_hz
2388 << " Hz"
Jonas Olsson6c9bc392020-01-14 14:54:352389 "\nNumber of channels:"
2390 "\n Render input: "
Jonas Olssonb2b20312020-01-14 11:11:312391 << render_input_num_channels
Jonas Olsson6c9bc392020-01-14 14:54:352392 << "\n Render output: " << render_output_num_channels
2393 << "\n Capture input: " << capture_input_num_channels
2394 << "\n Capture output: " << capture_output_num_channels;
Per Åhgren3e8bf282019-08-29 21:38:402395 return ss.Release();
2396}
2397
2398// Validates that running the audio processing module using various combinations
2399// of sample rates and number of channels works as intended.
2400void RunApmRateAndChannelTest(
2401 rtc::ArrayView<const int> sample_rates_hz,
2402 rtc::ArrayView<const int> render_channel_counts,
2403 rtc::ArrayView<const int> capture_channel_counts) {
Per Åhgren3e8bf282019-08-29 21:38:402404 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson3bd444f2022-08-03 12:37:002405 apm_config.pipeline.multi_channel_render = true;
2406 apm_config.pipeline.multi_channel_capture = true;
Per Åhgren3e8bf282019-08-29 21:38:402407 apm_config.echo_canceller.enabled = true;
Sam Zackrisson3bd444f2022-08-03 12:37:002408 rtc::scoped_refptr<AudioProcessing> apm =
2409 AudioProcessingBuilderForTesting().SetConfig(apm_config).Create();
Per Åhgren3e8bf282019-08-29 21:38:402410
2411 StreamConfig render_input_stream_config;
2412 StreamConfig render_output_stream_config;
2413 StreamConfig capture_input_stream_config;
2414 StreamConfig capture_output_stream_config;
2415
2416 std::vector<float> render_input_frame_channels;
2417 std::vector<float*> render_input_frame;
2418 std::vector<float> render_output_frame_channels;
2419 std::vector<float*> render_output_frame;
2420 std::vector<float> capture_input_frame_channels;
2421 std::vector<float*> capture_input_frame;
2422 std::vector<float> capture_output_frame_channels;
2423 std::vector<float*> capture_output_frame;
2424
2425 for (auto render_input_sample_rate_hz : sample_rates_hz) {
2426 for (auto render_output_sample_rate_hz : sample_rates_hz) {
2427 for (auto capture_input_sample_rate_hz : sample_rates_hz) {
2428 for (auto capture_output_sample_rate_hz : sample_rates_hz) {
2429 for (size_t render_input_num_channels : render_channel_counts) {
2430 for (size_t capture_input_num_channels : capture_channel_counts) {
2431 size_t render_output_num_channels = render_input_num_channels;
2432 size_t capture_output_num_channels = capture_input_num_channels;
2433 auto populate_audio_frame = [](int sample_rate_hz,
2434 size_t num_channels,
2435 StreamConfig* cfg,
2436 std::vector<float>* channels_data,
2437 std::vector<float*>* frame_data) {
2438 cfg->set_sample_rate_hz(sample_rate_hz);
2439 cfg->set_num_channels(num_channels);
Per Åhgren3e8bf282019-08-29 21:38:402440
Sam Zackrisson3bd444f2022-08-03 12:37:002441 size_t max_frame_size =
2442 AudioProcessing::GetFrameSize(sample_rate_hz);
Per Åhgren3e8bf282019-08-29 21:38:402443 channels_data->resize(num_channels * max_frame_size);
2444 std::fill(channels_data->begin(), channels_data->end(), 0.5f);
2445 frame_data->resize(num_channels);
2446 for (size_t channel = 0; channel < num_channels; ++channel) {
2447 (*frame_data)[channel] =
2448 &(*channels_data)[channel * max_frame_size];
2449 }
2450 };
2451
2452 populate_audio_frame(
2453 render_input_sample_rate_hz, render_input_num_channels,
2454 &render_input_stream_config, &render_input_frame_channels,
2455 &render_input_frame);
2456 populate_audio_frame(
2457 render_output_sample_rate_hz, render_output_num_channels,
2458 &render_output_stream_config, &render_output_frame_channels,
2459 &render_output_frame);
2460 populate_audio_frame(
2461 capture_input_sample_rate_hz, capture_input_num_channels,
2462 &capture_input_stream_config, &capture_input_frame_channels,
2463 &capture_input_frame);
2464 populate_audio_frame(
2465 capture_output_sample_rate_hz, capture_output_num_channels,
2466 &capture_output_stream_config, &capture_output_frame_channels,
2467 &capture_output_frame);
2468
2469 for (size_t frame = 0; frame < 2; ++frame) {
2470 SCOPED_TRACE(ProduceDebugText(
2471 render_input_sample_rate_hz, render_output_sample_rate_hz,
2472 capture_input_sample_rate_hz, capture_output_sample_rate_hz,
2473 render_input_num_channels, render_output_num_channels,
2474 render_input_num_channels, capture_output_num_channels));
2475
2476 int result = apm->ProcessReverseStream(
2477 &render_input_frame[0], render_input_stream_config,
2478 render_output_stream_config, &render_output_frame[0]);
2479 EXPECT_EQ(result, AudioProcessing::kNoError);
2480 result = apm->ProcessStream(
2481 &capture_input_frame[0], capture_input_stream_config,
2482 capture_output_stream_config, &capture_output_frame[0]);
2483 EXPECT_EQ(result, AudioProcessing::kNoError);
2484 }
2485 }
2486 }
2487 }
2488 }
2489 }
2490 }
2491}
2492
Alessio Bazzica3438a932020-10-14 10:47:502493constexpr void Toggle(bool& b) {
2494 b ^= true;
2495}
2496
niklase@google.com470e71d2011-07-07 08:21:252497} // namespace
peahc19f3122016-10-07 21:54:102498
Alessio Bazzicac054e782018-04-16 10:10:092499TEST(RuntimeSettingTest, TestDefaultCtor) {
2500 auto s = AudioProcessing::RuntimeSetting();
2501 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2502}
2503
Alessio Bazzicac054e782018-04-16 10:10:092504TEST(RuntimeSettingTest, TestUsageWithSwapQueue) {
2505 SwapQueue<AudioProcessing::RuntimeSetting> q(1);
2506 auto s = AudioProcessing::RuntimeSetting();
2507 ASSERT_TRUE(q.Insert(&s));
2508 ASSERT_TRUE(q.Remove(&s));
2509 EXPECT_EQ(AudioProcessing::RuntimeSetting::Type::kNotSpecified, s.type());
2510}
2511
Sam Zackrisson0beac582017-09-25 10:04:022512TEST(ApmConfiguration, EnablePostProcessing) {
2513 // Verify that apm uses a capture post processing module if one is provided.
Sam Zackrisson0beac582017-09-25 10:04:022514 auto mock_post_processor_ptr =
Mirko Bonadei6a489f22019-04-09 13:11:122515 new ::testing::NiceMock<test::MockCustomProcessing>();
Sam Zackrisson0beac582017-09-25 10:04:022516 auto mock_post_processor =
Alex Loiko5825aa62017-12-18 15:02:402517 std::unique_ptr<CustomProcessing>(mock_post_processor_ptr);
Ivo Creusen5ec7e122017-12-22 10:35:592518 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:172519 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 10:35:592520 .SetCapturePostProcessing(std::move(mock_post_processor))
Alex Loiko73ec0192018-05-15 08:52:282521 .Create();
Sam Zackrisson0beac582017-09-25 10:04:022522
Per Åhgren2507f8c2020-03-19 11:33:292523 Int16FrameData audio;
2524 audio.num_channels = 1;
Sam Zackrisson0beac582017-09-25 10:04:022525 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2526
Mirko Bonadei6a489f22019-04-09 13:11:122527 EXPECT_CALL(*mock_post_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 11:33:292528 apm->ProcessStream(audio.data.data(),
2529 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2530 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582531 audio.data.data());
Sam Zackrisson0beac582017-09-25 10:04:022532}
2533
Alex Loiko5825aa62017-12-18 15:02:402534TEST(ApmConfiguration, EnablePreProcessing) {
2535 // Verify that apm uses a capture post processing module if one is provided.
Alex Loiko5825aa62017-12-18 15:02:402536 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 13:11:122537 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko5825aa62017-12-18 15:02:402538 auto mock_pre_processor =
2539 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
Ivo Creusen62337e52018-01-09 13:17:332540 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:172541 AudioProcessingBuilderForTesting()
Ivo Creusen62337e52018-01-09 13:17:332542 .SetRenderPreProcessing(std::move(mock_pre_processor))
Alex Loiko73ec0192018-05-15 08:52:282543 .Create();
Alex Loiko5825aa62017-12-18 15:02:402544
Per Åhgren2507f8c2020-03-19 11:33:292545 Int16FrameData audio;
2546 audio.num_channels = 1;
Alex Loiko5825aa62017-12-18 15:02:402547 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2548
Mirko Bonadei6a489f22019-04-09 13:11:122549 EXPECT_CALL(*mock_pre_processor_ptr, Process(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 11:33:292550 apm->ProcessReverseStream(
2551 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2552 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2553 audio.data.data());
Alex Loiko5825aa62017-12-18 15:02:402554}
2555
Valeriia Nemychnikovaf06eb572018-08-29 08:37:092556TEST(ApmConfiguration, EnableCaptureAnalyzer) {
2557 // Verify that apm uses a capture analyzer if one is provided.
2558 auto mock_capture_analyzer_ptr =
Mirko Bonadei6a489f22019-04-09 13:11:122559 new ::testing::NiceMock<test::MockCustomAudioAnalyzer>();
Valeriia Nemychnikovaf06eb572018-08-29 08:37:092560 auto mock_capture_analyzer =
2561 std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
2562 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:172563 AudioProcessingBuilderForTesting()
Valeriia Nemychnikovaf06eb572018-08-29 08:37:092564 .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
2565 .Create();
2566
Per Åhgren2507f8c2020-03-19 11:33:292567 Int16FrameData audio;
2568 audio.num_channels = 1;
Valeriia Nemychnikovaf06eb572018-08-29 08:37:092569 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2570
Mirko Bonadei6a489f22019-04-09 13:11:122571 EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(::testing::_)).Times(1);
Per Åhgren2507f8c2020-03-19 11:33:292572 apm->ProcessStream(audio.data.data(),
2573 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2574 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582575 audio.data.data());
Valeriia Nemychnikovaf06eb572018-08-29 08:37:092576}
2577
Alex Loiko73ec0192018-05-15 08:52:282578TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
2579 auto mock_pre_processor_ptr =
Mirko Bonadei6a489f22019-04-09 13:11:122580 new ::testing::NiceMock<test::MockCustomProcessing>();
Alex Loiko73ec0192018-05-15 08:52:282581 auto mock_pre_processor =
2582 std::unique_ptr<CustomProcessing>(mock_pre_processor_ptr);
2583 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:172584 AudioProcessingBuilderForTesting()
Alex Loiko73ec0192018-05-15 08:52:282585 .SetRenderPreProcessing(std::move(mock_pre_processor))
2586 .Create();
2587 apm->SetRuntimeSetting(
2588 AudioProcessing::RuntimeSetting::CreateCustomRenderSetting(0));
2589
2590 // RuntimeSettings forwarded during 'Process*Stream' calls.
2591 // Therefore we have to make one such call.
Per Åhgren2507f8c2020-03-19 11:33:292592 Int16FrameData audio;
2593 audio.num_channels = 1;
Alex Loiko73ec0192018-05-15 08:52:282594 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
2595
Mirko Bonadei6a489f22019-04-09 13:11:122596 EXPECT_CALL(*mock_pre_processor_ptr, SetRuntimeSetting(::testing::_))
2597 .Times(1);
Per Åhgren2507f8c2020-03-19 11:33:292598 apm->ProcessReverseStream(
2599 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2600 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2601 audio.data.data());
Alex Loiko73ec0192018-05-15 08:52:282602}
2603
Gustaf Ullberg002ef282017-10-12 13:13:172604class MyEchoControlFactory : public EchoControlFactory {
2605 public:
2606 std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
2607 auto ec = new test::MockEchoControl();
Mirko Bonadei6a489f22019-04-09 13:11:122608 EXPECT_CALL(*ec, AnalyzeRender(::testing::_)).Times(1);
2609 EXPECT_CALL(*ec, AnalyzeCapture(::testing::_)).Times(2);
Per Åhgrenc20a19c2019-11-13 10:12:292610 EXPECT_CALL(*ec, ProcessCapture(::testing::_, ::testing::_, ::testing::_))
2611 .Times(2);
Gustaf Ullberg002ef282017-10-12 13:13:172612 return std::unique_ptr<EchoControl>(ec);
2613 }
Per Åhgrence202a02019-09-02 15:01:192614
2615 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
Per Åhgren4e5c7092019-11-01 19:44:112616 int num_render_channels,
2617 int num_capture_channels) {
Per Åhgrence202a02019-09-02 15:01:192618 return Create(sample_rate_hz);
2619 }
Gustaf Ullberg002ef282017-10-12 13:13:172620};
2621
2622TEST(ApmConfiguration, EchoControlInjection) {
2623 // Verify that apm uses an injected echo controller if one is provided.
Gustaf Ullberg002ef282017-10-12 13:13:172624 std::unique_ptr<EchoControlFactory> echo_control_factory(
2625 new MyEchoControlFactory());
2626
Alex Loiko5825aa62017-12-18 15:02:402627 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:172628 AudioProcessingBuilderForTesting()
Ivo Creusen5ec7e122017-12-22 10:35:592629 .SetEchoControlFactory(std::move(echo_control_factory))
Alessio Bazzicabe1b8982021-09-17 06:26:102630 .Create();
Gustaf Ullberg002ef282017-10-12 13:13:172631
Per Åhgren2507f8c2020-03-19 11:33:292632 Int16FrameData audio;
2633 audio.num_channels = 1;
Gustaf Ullberg002ef282017-10-12 13:13:172634 SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
Per Åhgren2507f8c2020-03-19 11:33:292635 apm->ProcessStream(audio.data.data(),
2636 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2637 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582638 audio.data.data());
Per Åhgren2507f8c2020-03-19 11:33:292639 apm->ProcessReverseStream(
2640 audio.data.data(), StreamConfig(audio.sample_rate_hz, audio.num_channels),
2641 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2642 audio.data.data());
2643 apm->ProcessStream(audio.data.data(),
2644 StreamConfig(audio.sample_rate_hz, audio.num_channels),
2645 StreamConfig(audio.sample_rate_hz, audio.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582646 audio.data.data());
Gustaf Ullberg002ef282017-10-12 13:13:172647}
Ivo Creusenae0260962017-11-20 12:07:162648
Sam Zackrisson03cb7e52021-12-06 14:40:042649TEST(ApmConfiguration, EchoDetectorInjection) {
2650 using ::testing::_;
2651 rtc::scoped_refptr<test::MockEchoDetector> mock_echo_detector =
2652 rtc::make_ref_counted<::testing::StrictMock<test::MockEchoDetector>>();
2653 EXPECT_CALL(*mock_echo_detector,
2654 Initialize(/*capture_sample_rate_hz=*/16000, _,
2655 /*render_sample_rate_hz=*/16000, _))
2656 .Times(1);
Niels Möller4f776ac2021-07-02 09:30:542657 rtc::scoped_refptr<AudioProcessing> apm =
Sam Zackrisson03cb7e52021-12-06 14:40:042658 AudioProcessingBuilderForTesting()
2659 .SetEchoDetector(mock_echo_detector)
2660 .Create();
2661
2662 // The echo detector is included in processing when enabled.
2663 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2664 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2665 EXPECT_EQ(render_audio.size(), 160u);
2666 });
2667 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2668 .WillOnce([](rtc::ArrayView<const float> capture_audio) {
2669 EXPECT_EQ(capture_audio.size(), 160u);
2670 });
2671 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(1);
2672
2673 Int16FrameData frame;
2674 frame.num_channels = 1;
2675 SetFrameSampleRate(&frame, 16000);
2676
2677 apm->ProcessReverseStream(frame.data.data(), StreamConfig(16000, 1),
2678 StreamConfig(16000, 1), frame.data.data());
2679 apm->ProcessStream(frame.data.data(), StreamConfig(16000, 1),
2680 StreamConfig(16000, 1), frame.data.data());
2681
2682 // When processing rates change, the echo detector is also reinitialized to
2683 // match those.
2684 EXPECT_CALL(*mock_echo_detector,
2685 Initialize(/*capture_sample_rate_hz=*/48000, _,
2686 /*render_sample_rate_hz=*/16000, _))
2687 .Times(1);
2688 EXPECT_CALL(*mock_echo_detector,
2689 Initialize(/*capture_sample_rate_hz=*/48000, _,
2690 /*render_sample_rate_hz=*/48000, _))
2691 .Times(1);
2692 EXPECT_CALL(*mock_echo_detector, AnalyzeRenderAudio(_))
2693 .WillOnce([](rtc::ArrayView<const float> render_audio) {
2694 EXPECT_EQ(render_audio.size(), 480u);
2695 });
2696 EXPECT_CALL(*mock_echo_detector, AnalyzeCaptureAudio(_))
2697 .Times(2)
2698 .WillRepeatedly([](rtc::ArrayView<const float> capture_audio) {
2699 EXPECT_EQ(capture_audio.size(), 480u);
2700 });
2701 EXPECT_CALL(*mock_echo_detector, GetMetrics()).Times(2);
2702
2703 SetFrameSampleRate(&frame, 48000);
2704 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2705 StreamConfig(48000, 1), frame.data.data());
2706 apm->ProcessReverseStream(frame.data.data(), StreamConfig(48000, 1),
2707 StreamConfig(48000, 1), frame.data.data());
2708 apm->ProcessStream(frame.data.data(), StreamConfig(48000, 1),
2709 StreamConfig(48000, 1), frame.data.data());
2710}
2711
2712rtc::scoped_refptr<AudioProcessing> CreateApm(bool mobile_aec) {
2713 // Enable residual echo detection, for stats.
2714 rtc::scoped_refptr<AudioProcessing> apm =
2715 AudioProcessingBuilderForTesting()
2716 .SetEchoDetector(CreateEchoDetector())
2717 .Create();
Ivo Creusenae0260962017-11-20 12:07:162718 if (!apm) {
2719 return apm;
2720 }
2721
2722 ProcessingConfig processing_config = {
2723 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
2724
2725 if (apm->Initialize(processing_config) != 0) {
2726 return nullptr;
2727 }
2728
Sam Zackrisson03cb7e52021-12-06 14:40:042729 // Disable all components except for an AEC.
Sam Zackrissoncdf0e6d2018-09-17 09:05:172730 AudioProcessing::Config apm_config;
Sam Zackrissoncdf0e6d2018-09-17 09:05:172731 apm_config.high_pass_filter.enabled = false;
Sam Zackrisson41478c72019-10-15 08:10:262732 apm_config.gain_controller1.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 09:05:172733 apm_config.gain_controller2.enabled = false;
2734 apm_config.echo_canceller.enabled = true;
Per Åhgren8607f842019-04-12 20:02:262735 apm_config.echo_canceller.mobile_mode = mobile_aec;
saza0bad15f2019-10-16 09:46:112736 apm_config.noise_suppression.enabled = false;
Sam Zackrissoncdf0e6d2018-09-17 09:05:172737 apm->ApplyConfig(apm_config);
Ivo Creusenae0260962017-11-20 12:07:162738 return apm;
2739}
2740
2741#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_MAC)
2742#define MAYBE_ApmStatistics DISABLED_ApmStatistics
2743#else
2744#define MAYBE_ApmStatistics ApmStatistics
2745#endif
2746
Per Åhgren8607f842019-04-12 20:02:262747TEST(MAYBE_ApmStatistics, AECEnabledTest) {
2748 // Set up APM with AEC3 and process some audio.
Niels Möller4f776ac2021-07-02 09:30:542749 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(false);
Ivo Creusenae0260962017-11-20 12:07:162750 ASSERT_TRUE(apm);
Per Åhgren200feba1c2019-03-06 03:16:462751 AudioProcessing::Config apm_config;
2752 apm_config.echo_canceller.enabled = true;
Per Åhgren200feba1c2019-03-06 03:16:462753 apm->ApplyConfig(apm_config);
Ivo Creusenae0260962017-11-20 12:07:162754
2755 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 11:33:292756 Int16FrameData frame;
2757 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 15:29:272758 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae0260962017-11-20 12:07:162759
2760 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 11:33:292761 int16_t* ptr = frame.data.data();
Ivo Creusenae0260962017-11-20 12:07:162762 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2763 ptr[i] = 10000 * ((i % 3) - 1);
2764 }
2765
2766 // Do some processing.
2767 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 11:33:292768 EXPECT_EQ(apm->ProcessReverseStream(
2769 frame.data.data(),
2770 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2771 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2772 frame.data.data()),
2773 0);
Ivo Creusenae0260962017-11-20 12:07:162774 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 11:33:292775 EXPECT_EQ(apm->ProcessStream(
2776 frame.data.data(),
2777 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2778 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582779 frame.data.data()),
Per Åhgren2507f8c2020-03-19 11:33:292780 0);
Ivo Creusenae0260962017-11-20 12:07:162781 }
2782
2783 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 13:32:142784 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae0260962017-11-20 12:07:162785 // We expect all statistics to be set and have a sensible value.
Sam Zackrisson03cb7e52021-12-06 14:40:042786 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
Ivo Creusenae0260962017-11-20 12:07:162787 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2788 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
Sam Zackrisson03cb7e52021-12-06 14:40:042789 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
Ivo Creusenae0260962017-11-20 12:07:162790 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2791 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
Sam Zackrisson03cb7e52021-12-06 14:40:042792 ASSERT_TRUE(stats.echo_return_loss.has_value());
Ivo Creusenae0260962017-11-20 12:07:162793 EXPECT_NE(*stats.echo_return_loss, -100.0);
Sam Zackrisson03cb7e52021-12-06 14:40:042794 ASSERT_TRUE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae0260962017-11-20 12:07:162795 EXPECT_NE(*stats.echo_return_loss_enhancement, -100.0);
Ivo Creusenae0260962017-11-20 12:07:162796}
2797
2798TEST(MAYBE_ApmStatistics, AECMEnabledTest) {
2799 // Set up APM with AECM and process some audio.
Niels Möller4f776ac2021-07-02 09:30:542800 rtc::scoped_refptr<AudioProcessing> apm = CreateApm(true);
Ivo Creusenae0260962017-11-20 12:07:162801 ASSERT_TRUE(apm);
2802
2803 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 11:33:292804 Int16FrameData frame;
2805 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 15:29:272806 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
Ivo Creusenae0260962017-11-20 12:07:162807
2808 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 11:33:292809 int16_t* ptr = frame.data.data();
Ivo Creusenae0260962017-11-20 12:07:162810 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2811 ptr[i] = 10000 * ((i % 3) - 1);
2812 }
2813
2814 // Do some processing.
2815 for (int i = 0; i < 200; i++) {
Per Åhgren2507f8c2020-03-19 11:33:292816 EXPECT_EQ(apm->ProcessReverseStream(
2817 frame.data.data(),
2818 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2819 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2820 frame.data.data()),
2821 0);
Ivo Creusenae0260962017-11-20 12:07:162822 EXPECT_EQ(apm->set_stream_delay_ms(0), 0);
Per Åhgren2507f8c2020-03-19 11:33:292823 EXPECT_EQ(apm->ProcessStream(
2824 frame.data.data(),
2825 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2826 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582827 frame.data.data()),
Per Åhgren2507f8c2020-03-19 11:33:292828 0);
Ivo Creusenae0260962017-11-20 12:07:162829 }
2830
2831 // Test statistics interface.
Per Åhgrencf4c8722019-12-30 13:32:142832 AudioProcessingStats stats = apm->GetStatistics();
Ivo Creusenae0260962017-11-20 12:07:162833 // We expect only the residual echo detector statistics to be set and have a
2834 // sensible value.
Sam Zackrisson03cb7e52021-12-06 14:40:042835 ASSERT_TRUE(stats.residual_echo_likelihood.has_value());
2836 EXPECT_GE(*stats.residual_echo_likelihood, 0.0);
2837 EXPECT_LE(*stats.residual_echo_likelihood, 1.0);
2838 ASSERT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2839 EXPECT_GE(*stats.residual_echo_likelihood_recent_max, 0.0);
2840 EXPECT_LE(*stats.residual_echo_likelihood_recent_max, 1.0);
2841 EXPECT_FALSE(stats.echo_return_loss.has_value());
2842 EXPECT_FALSE(stats.echo_return_loss_enhancement.has_value());
Ivo Creusenae0260962017-11-20 12:07:162843}
Sam Zackrissonb24c00f2018-11-26 15:18:252844
Alessio Bazzica1db0a262022-02-15 14:18:092845TEST(ApmStatistics, DoNotReportVoiceDetectedStat) {
Sam Zackrisson4db667b2018-12-21 15:29:272846 ProcessingConfig processing_config = {
2847 {{32000, 1}, {32000, 1}, {32000, 1}, {32000, 1}}};
Sam Zackrisson4db667b2018-12-21 15:29:272848
2849 // Set up an audioframe.
Per Åhgren2507f8c2020-03-19 11:33:292850 Int16FrameData frame;
2851 frame.num_channels = 1;
Sam Zackrisson4db667b2018-12-21 15:29:272852 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2853
2854 // Fill the audio frame with a sawtooth pattern.
Per Åhgren2507f8c2020-03-19 11:33:292855 int16_t* ptr = frame.data.data();
Sam Zackrisson4db667b2018-12-21 15:29:272856 for (size_t i = 0; i < frame.kMaxDataSizeSamples; i++) {
2857 ptr[i] = 10000 * ((i % 3) - 1);
2858 }
2859
Niels Möller4f776ac2021-07-02 09:30:542860 rtc::scoped_refptr<AudioProcessing> apm =
2861 AudioProcessingBuilderForTesting().Create();
Sam Zackrisson4db667b2018-12-21 15:29:272862 apm->Initialize(processing_config);
2863
Alessio Bazzica1db0a262022-02-15 14:18:092864 // No metric should be reported.
Per Åhgren2507f8c2020-03-19 11:33:292865 EXPECT_EQ(
2866 apm->ProcessStream(frame.data.data(),
2867 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2868 StreamConfig(frame.sample_rate_hz, frame.num_channels),
Per Åhgrendc5522b2020-03-19 13:55:582869 frame.data.data()),
Per Åhgren2507f8c2020-03-19 11:33:292870 0);
Alessio Bazzica1db0a262022-02-15 14:18:092871 EXPECT_FALSE(apm->GetStatistics().voice_detected.has_value());
Sam Zackrisson4db667b2018-12-21 15:29:272872}
Per Åhgren3e8bf282019-08-29 21:38:402873
Sam Zackrisson03cb7e52021-12-06 14:40:042874TEST(ApmStatistics, GetStatisticsReportsNoEchoDetectorStatsWhenDisabled) {
2875 rtc::scoped_refptr<AudioProcessing> apm =
2876 AudioProcessingBuilderForTesting().Create();
2877 Int16FrameData frame;
2878 frame.num_channels = 1;
2879 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2880 ASSERT_EQ(
2881 apm->ProcessStream(frame.data.data(),
2882 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2883 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2884 frame.data.data()),
2885 0);
2886 // Echo detector is disabled by default, no stats reported.
2887 AudioProcessingStats stats = apm->GetStatistics();
2888 EXPECT_FALSE(stats.residual_echo_likelihood.has_value());
2889 EXPECT_FALSE(stats.residual_echo_likelihood_recent_max.has_value());
2890}
2891
2892TEST(ApmStatistics, GetStatisticsReportsEchoDetectorStatsWhenEnabled) {
2893 // Create APM with an echo detector injected.
2894 rtc::scoped_refptr<AudioProcessing> apm =
2895 AudioProcessingBuilderForTesting()
2896 .SetEchoDetector(CreateEchoDetector())
2897 .Create();
2898 Int16FrameData frame;
2899 frame.num_channels = 1;
2900 SetFrameSampleRate(&frame, AudioProcessing::NativeRate::kSampleRate32kHz);
2901 // Echo detector enabled: Report stats.
2902 ASSERT_EQ(
2903 apm->ProcessStream(frame.data.data(),
2904 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2905 StreamConfig(frame.sample_rate_hz, frame.num_channels),
2906 frame.data.data()),
2907 0);
2908 AudioProcessingStats stats = apm->GetStatistics();
2909 EXPECT_TRUE(stats.residual_echo_likelihood.has_value());
2910 EXPECT_TRUE(stats.residual_echo_likelihood_recent_max.has_value());
2911}
2912
Per Åhgren3e8bf282019-08-29 21:38:402913TEST(ApmConfiguration, HandlingOfRateAndChannelCombinations) {
2914 std::array<int, 3> sample_rates_hz = {16000, 32000, 48000};
2915 std::array<int, 2> render_channel_counts = {1, 7};
2916 std::array<int, 2> capture_channel_counts = {1, 7};
2917 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2918 capture_channel_counts);
2919}
2920
2921TEST(ApmConfiguration, HandlingOfChannelCombinations) {
2922 std::array<int, 1> sample_rates_hz = {48000};
2923 std::array<int, 8> render_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2924 std::array<int, 8> capture_channel_counts = {1, 2, 3, 4, 5, 6, 7, 8};
2925 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2926 capture_channel_counts);
2927}
2928
2929TEST(ApmConfiguration, HandlingOfRateCombinations) {
Sam Zackrisson3bd444f2022-08-03 12:37:002930 // Test rates <= 96000 logged by Chrome UMA:
2931 // - WebRTC.AudioInputSampleRate
2932 // - WebRTC.AudioOutputSampleRate
2933 // Higher rates are tested in AudioProcessingTest.Format, to keep the number
2934 // of combinations in this test manageable.
2935 std::array<int, 9> sample_rates_hz = {8000, 11025, 16000, 22050, 32000,
2936 44100, 48000, 88200, 96000};
Per Åhgren3e8bf282019-08-29 21:38:402937 std::array<int, 1> render_channel_counts = {2};
2938 std::array<int, 1> capture_channel_counts = {2};
2939 RunApmRateAndChannelTest(sample_rates_hz, render_channel_counts,
2940 capture_channel_counts);
2941}
2942
Yves Gerey1fce3f82019-12-05 16:45:312943TEST(ApmConfiguration, SelfAssignment) {
2944 // At some point memory sanitizer was complaining about self-assigment.
2945 // Make sure we don't regress.
2946 AudioProcessing::Config config;
2947 AudioProcessing::Config* config2 = &config;
2948 *config2 = *config2; // Workaround -Wself-assign-overloaded
2949 SUCCEED(); // Real success is absence of defects from asan/msan/ubsan.
2950}
2951
Alessio Bazzica3438a932020-10-14 10:47:502952TEST(AudioProcessing, GainController1ConfigEqual) {
2953 AudioProcessing::Config::GainController1 a;
2954 AudioProcessing::Config::GainController1 b;
2955 EXPECT_EQ(a, b);
2956
2957 Toggle(a.enabled);
2958 b.enabled = a.enabled;
2959 EXPECT_EQ(a, b);
2960
2961 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
2962 b.mode = a.mode;
2963 EXPECT_EQ(a, b);
2964
2965 a.target_level_dbfs++;
2966 b.target_level_dbfs = a.target_level_dbfs;
2967 EXPECT_EQ(a, b);
2968
2969 a.compression_gain_db++;
2970 b.compression_gain_db = a.compression_gain_db;
2971 EXPECT_EQ(a, b);
2972
2973 Toggle(a.enable_limiter);
2974 b.enable_limiter = a.enable_limiter;
2975 EXPECT_EQ(a, b);
2976
Alessio Bazzica3438a932020-10-14 10:47:502977 auto& a_analog = a.analog_gain_controller;
2978 auto& b_analog = b.analog_gain_controller;
2979
2980 Toggle(a_analog.enabled);
2981 b_analog.enabled = a_analog.enabled;
2982 EXPECT_EQ(a, b);
2983
2984 a_analog.startup_min_volume++;
2985 b_analog.startup_min_volume = a_analog.startup_min_volume;
2986 EXPECT_EQ(a, b);
2987
2988 a_analog.clipped_level_min++;
2989 b_analog.clipped_level_min = a_analog.clipped_level_min;
2990 EXPECT_EQ(a, b);
2991
Alessio Bazzica3438a932020-10-14 10:47:502992 Toggle(a_analog.enable_digital_adaptive);
2993 b_analog.enable_digital_adaptive = a_analog.enable_digital_adaptive;
2994 EXPECT_EQ(a, b);
2995}
2996
2997// Checks that one differing parameter is sufficient to make two configs
2998// different.
2999TEST(AudioProcessing, GainController1ConfigNotEqual) {
3000 AudioProcessing::Config::GainController1 a;
3001 const AudioProcessing::Config::GainController1 b;
3002
3003 Toggle(a.enabled);
3004 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493005 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503006
3007 a.mode = AudioProcessing::Config::GainController1::Mode::kAdaptiveDigital;
3008 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493009 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503010
3011 a.target_level_dbfs++;
3012 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493013 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503014
3015 a.compression_gain_db++;
3016 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493017 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503018
3019 Toggle(a.enable_limiter);
3020 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493021 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503022
Alessio Bazzica3438a932020-10-14 10:47:503023 auto& a_analog = a.analog_gain_controller;
3024 const auto& b_analog = b.analog_gain_controller;
3025
3026 Toggle(a_analog.enabled);
3027 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493028 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 10:47:503029
3030 a_analog.startup_min_volume++;
3031 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493032 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 10:47:503033
3034 a_analog.clipped_level_min++;
3035 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493036 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 10:47:503037
Alessio Bazzica3438a932020-10-14 10:47:503038 Toggle(a_analog.enable_digital_adaptive);
3039 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493040 a_analog = b_analog;
Alessio Bazzica3438a932020-10-14 10:47:503041}
3042
3043TEST(AudioProcessing, GainController2ConfigEqual) {
3044 AudioProcessing::Config::GainController2 a;
3045 AudioProcessing::Config::GainController2 b;
3046 EXPECT_EQ(a, b);
3047
3048 Toggle(a.enabled);
3049 b.enabled = a.enabled;
3050 EXPECT_EQ(a, b);
3051
Alessio Bazzicaa2efd152021-04-29 14:17:493052 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503053 b.fixed_digital.gain_db = a.fixed_digital.gain_db;
3054 EXPECT_EQ(a, b);
3055
3056 auto& a_adaptive = a.adaptive_digital;
3057 auto& b_adaptive = b.adaptive_digital;
3058
3059 Toggle(a_adaptive.enabled);
3060 b_adaptive.enabled = a_adaptive.enabled;
3061 EXPECT_EQ(a, b);
3062
Alessio Bazzicaa850e6c2021-10-04 11:35:553063 a_adaptive.headroom_db += 1.0f;
3064 b_adaptive.headroom_db = a_adaptive.headroom_db;
3065 EXPECT_EQ(a, b);
3066
3067 a_adaptive.max_gain_db += 1.0f;
3068 b_adaptive.max_gain_db = a_adaptive.max_gain_db;
3069 EXPECT_EQ(a, b);
3070
3071 a_adaptive.initial_gain_db += 1.0f;
3072 b_adaptive.initial_gain_db = a_adaptive.initial_gain_db;
3073 EXPECT_EQ(a, b);
3074
Alessio Bazzicaa2efd152021-04-29 14:17:493075 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503076 b_adaptive.max_gain_change_db_per_second =
3077 a_adaptive.max_gain_change_db_per_second;
3078 EXPECT_EQ(a, b);
3079
Alessio Bazzicaa2efd152021-04-29 14:17:493080 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503081 b_adaptive.max_output_noise_level_dbfs =
3082 a_adaptive.max_output_noise_level_dbfs;
3083 EXPECT_EQ(a, b);
3084}
3085
3086// Checks that one differing parameter is sufficient to make two configs
3087// different.
3088TEST(AudioProcessing, GainController2ConfigNotEqual) {
3089 AudioProcessing::Config::GainController2 a;
3090 const AudioProcessing::Config::GainController2 b;
3091
3092 Toggle(a.enabled);
3093 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493094 a = b;
Alessio Bazzica3438a932020-10-14 10:47:503095
Alessio Bazzicaa2efd152021-04-29 14:17:493096 a.fixed_digital.gain_db += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503097 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493098 a.fixed_digital = b.fixed_digital;
Alessio Bazzica3438a932020-10-14 10:47:503099
3100 auto& a_adaptive = a.adaptive_digital;
3101 const auto& b_adaptive = b.adaptive_digital;
3102
3103 Toggle(a_adaptive.enabled);
3104 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493105 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 10:47:503106
Alessio Bazzicaa850e6c2021-10-04 11:35:553107 a_adaptive.headroom_db += 1.0f;
3108 EXPECT_NE(a, b);
3109 a_adaptive = b_adaptive;
3110
3111 a_adaptive.max_gain_db += 1.0f;
3112 EXPECT_NE(a, b);
3113 a_adaptive = b_adaptive;
3114
3115 a_adaptive.initial_gain_db += 1.0f;
3116 EXPECT_NE(a, b);
3117 a_adaptive = b_adaptive;
3118
Alessio Bazzicaa2efd152021-04-29 14:17:493119 a_adaptive.max_gain_change_db_per_second += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503120 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493121 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 10:47:503122
Alessio Bazzicaa2efd152021-04-29 14:17:493123 a_adaptive.max_output_noise_level_dbfs += 1.0f;
Alessio Bazzica3438a932020-10-14 10:47:503124 EXPECT_NE(a, b);
Alessio Bazzicaa2efd152021-04-29 14:17:493125 a_adaptive = b_adaptive;
Alessio Bazzica3438a932020-10-14 10:47:503126}
3127
Sam Zackrisson5dd54822022-11-17 10:26:583128struct ApmFormatHandlingTestParams {
3129 enum class ExpectedOutput {
3130 kErrorAndUnmodified,
3131 kErrorAndSilence,
3132 kErrorAndCopyOfFirstChannel,
3133 kErrorAndExactCopy,
3134 kNoError
3135 };
3136
3137 StreamConfig input_config;
3138 StreamConfig output_config;
3139 ExpectedOutput expected_output;
3140};
3141
3142class ApmFormatHandlingTest
3143 : public ::testing::TestWithParam<
3144 std::tuple<StreamDirection, ApmFormatHandlingTestParams>> {
3145 public:
3146 ApmFormatHandlingTest()
3147 : stream_direction_(std::get<0>(GetParam())),
3148 test_params_(std::get<1>(GetParam())) {}
3149
3150 protected:
3151 ::testing::Message ProduceDebugMessage() {
3152 return ::testing::Message()
3153 << "input sample_rate_hz="
3154 << test_params_.input_config.sample_rate_hz()
3155 << " num_channels=" << test_params_.input_config.num_channels()
3156 << ", output sample_rate_hz="
3157 << test_params_.output_config.sample_rate_hz()
3158 << " num_channels=" << test_params_.output_config.num_channels()
3159 << ", stream_direction=" << stream_direction_ << ", expected_output="
3160 << static_cast<int>(test_params_.expected_output);
3161 }
3162
3163 StreamDirection stream_direction_;
3164 ApmFormatHandlingTestParams test_params_;
3165};
3166
3167INSTANTIATE_TEST_SUITE_P(
3168 FormatValidation,
3169 ApmFormatHandlingTest,
3170 testing::Combine(
3171 ::testing::Values(kForward, kReverse),
3172 ::testing::Values(
3173 // Test cases with values on the boundary of legal ranges.
3174 ApmFormatHandlingTestParams{
3175 StreamConfig(16000, 1), StreamConfig(8000, 1),
3176 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3177 ApmFormatHandlingTestParams{
3178 StreamConfig(8000, 1), StreamConfig(16000, 1),
3179 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3180 ApmFormatHandlingTestParams{
3181 StreamConfig(384000, 1), StreamConfig(16000, 1),
3182 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3183 ApmFormatHandlingTestParams{
3184 StreamConfig(16000, 1), StreamConfig(384000, 1),
3185 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3186 ApmFormatHandlingTestParams{
3187 StreamConfig(16000, 2), StreamConfig(16000, 1),
3188 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3189 ApmFormatHandlingTestParams{
3190 StreamConfig(16000, 3), StreamConfig(16000, 3),
3191 ApmFormatHandlingTestParams::ExpectedOutput::kNoError},
3192
Sam Zackrisson06cba442022-11-21 15:32:423193 // Supported but incompatible formats.
3194 ApmFormatHandlingTestParams{
3195 StreamConfig(16000, 3), StreamConfig(16000, 2),
3196 ApmFormatHandlingTestParams::ExpectedOutput::
3197 kErrorAndCopyOfFirstChannel},
3198 ApmFormatHandlingTestParams{
3199 StreamConfig(16000, 3), StreamConfig(16000, 4),
3200 ApmFormatHandlingTestParams::ExpectedOutput::
3201 kErrorAndCopyOfFirstChannel},
3202
Sam Zackrisson5dd54822022-11-17 10:26:583203 // Unsupported format and input / output mismatch.
3204 ApmFormatHandlingTestParams{
3205 StreamConfig(7900, 1), StreamConfig(16000, 1),
3206 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3207 ApmFormatHandlingTestParams{
3208 StreamConfig(16000, 1), StreamConfig(7900, 1),
3209 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3210 ApmFormatHandlingTestParams{
3211 StreamConfig(390000, 1), StreamConfig(16000, 1),
3212 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3213 ApmFormatHandlingTestParams{
3214 StreamConfig(16000, 1), StreamConfig(390000, 1),
3215 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3216 ApmFormatHandlingTestParams{
3217 StreamConfig(-16000, 1), StreamConfig(16000, 1),
3218 ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence},
3219
3220 // Unsupported format but input / output formats match.
3221 ApmFormatHandlingTestParams{StreamConfig(7900, 1),
3222 StreamConfig(7900, 1),
3223 ApmFormatHandlingTestParams::
3224 ExpectedOutput::kErrorAndExactCopy},
3225 ApmFormatHandlingTestParams{StreamConfig(390000, 1),
3226 StreamConfig(390000, 1),
3227 ApmFormatHandlingTestParams::
3228 ExpectedOutput::kErrorAndExactCopy},
3229
3230 // Unsupported but identical sample rate, channel mismatch.
3231 ApmFormatHandlingTestParams{
3232 StreamConfig(7900, 1), StreamConfig(7900, 2),
3233 ApmFormatHandlingTestParams::ExpectedOutput::
3234 kErrorAndCopyOfFirstChannel},
3235 ApmFormatHandlingTestParams{
3236 StreamConfig(7900, 2), StreamConfig(7900, 1),
3237 ApmFormatHandlingTestParams::ExpectedOutput::
3238 kErrorAndCopyOfFirstChannel},
3239
3240 // Test cases with meaningless output format.
3241 ApmFormatHandlingTestParams{
3242 StreamConfig(16000, 1), StreamConfig(-16000, 1),
3243 ApmFormatHandlingTestParams::ExpectedOutput::
3244 kErrorAndUnmodified},
3245 ApmFormatHandlingTestParams{
3246 StreamConfig(-16000, 1), StreamConfig(-16000, 1),
3247 ApmFormatHandlingTestParams::ExpectedOutput::
3248 kErrorAndUnmodified})));
3249
3250TEST_P(ApmFormatHandlingTest, IntApi) {
3251 SCOPED_TRACE(ProduceDebugMessage());
3252
3253 // Set up input and output data.
3254 const size_t num_input_samples =
3255 test_params_.input_config.num_channels() *
3256 std::abs(test_params_.input_config.sample_rate_hz() / 100);
3257 const size_t num_output_samples =
3258 test_params_.output_config.num_channels() *
3259 std::abs(test_params_.output_config.sample_rate_hz() / 100);
3260 std::vector<int16_t> input_block(num_input_samples);
3261 for (int i = 0; i < static_cast<int>(input_block.size()); ++i) {
3262 input_block[i] = i;
3263 }
3264 std::vector<int16_t> output_block(num_output_samples);
3265 constexpr int kUnlikelyOffset = 37;
3266 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3267 output_block[i] = i - kUnlikelyOffset;
3268 }
3269
3270 // Call APM.
3271 rtc::scoped_refptr<AudioProcessing> ap =
3272 AudioProcessingBuilderForTesting().Create();
3273 int error;
3274 if (stream_direction_ == kForward) {
3275 error = ap->ProcessStream(input_block.data(), test_params_.input_config,
3276 test_params_.output_config, output_block.data());
3277 } else {
3278 error = ap->ProcessReverseStream(
3279 input_block.data(), test_params_.input_config,
3280 test_params_.output_config, output_block.data());
3281 }
3282
3283 // Check output.
3284 switch (test_params_.expected_output) {
3285 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError:
3286 EXPECT_EQ(error, AudioProcessing::kNoError);
3287 break;
3288 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified:
3289 EXPECT_NE(error, AudioProcessing::kNoError);
3290 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3291 EXPECT_EQ(output_block[i], i - kUnlikelyOffset);
3292 }
3293 break;
3294 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence:
3295 EXPECT_NE(error, AudioProcessing::kNoError);
3296 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3297 EXPECT_EQ(output_block[i], 0);
3298 }
3299 break;
3300 case ApmFormatHandlingTestParams::ExpectedOutput::
3301 kErrorAndCopyOfFirstChannel:
3302 EXPECT_NE(error, AudioProcessing::kNoError);
3303 for (size_t ch = 0; ch < test_params_.output_config.num_channels();
3304 ++ch) {
3305 for (size_t i = 0; i < test_params_.output_config.num_frames(); ++i) {
3306 EXPECT_EQ(
3307 output_block[ch + i * test_params_.output_config.num_channels()],
3308 static_cast<int16_t>(i *
3309 test_params_.input_config.num_channels()));
3310 }
3311 }
3312 break;
3313 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy:
3314 EXPECT_NE(error, AudioProcessing::kNoError);
3315 for (int i = 0; i < static_cast<int>(output_block.size()); ++i) {
3316 EXPECT_EQ(output_block[i], i);
3317 }
3318 break;
3319 }
3320}
3321
3322TEST_P(ApmFormatHandlingTest, FloatApi) {
3323 SCOPED_TRACE(ProduceDebugMessage());
3324
3325 // Set up input and output data.
3326 const size_t input_samples_per_channel =
3327 std::abs(test_params_.input_config.sample_rate_hz()) / 100;
3328 const size_t output_samples_per_channel =
3329 std::abs(test_params_.output_config.sample_rate_hz()) / 100;
3330 const size_t input_num_channels = test_params_.input_config.num_channels();
3331 const size_t output_num_channels = test_params_.output_config.num_channels();
3332 ChannelBuffer<float> input_block(input_samples_per_channel,
3333 input_num_channels);
3334 ChannelBuffer<float> output_block(output_samples_per_channel,
3335 output_num_channels);
3336 for (size_t ch = 0; ch < input_num_channels; ++ch) {
3337 for (size_t i = 0; i < input_samples_per_channel; ++i) {
3338 input_block.channels()[ch][i] = ch + i * input_num_channels;
3339 }
3340 }
3341 constexpr int kUnlikelyOffset = 37;
3342 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3343 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3344 output_block.channels()[ch][i] =
3345 ch + i * output_num_channels - kUnlikelyOffset;
3346 }
3347 }
3348
3349 // Call APM.
3350 rtc::scoped_refptr<AudioProcessing> ap =
3351 AudioProcessingBuilderForTesting().Create();
3352 int error;
3353 if (stream_direction_ == kForward) {
3354 error =
3355 ap->ProcessStream(input_block.channels(), test_params_.input_config,
3356 test_params_.output_config, output_block.channels());
3357 } else {
3358 error = ap->ProcessReverseStream(
3359 input_block.channels(), test_params_.input_config,
3360 test_params_.output_config, output_block.channels());
3361 }
3362
3363 // Check output.
3364 switch (test_params_.expected_output) {
3365 case ApmFormatHandlingTestParams::ExpectedOutput::kNoError:
3366 EXPECT_EQ(error, AudioProcessing::kNoError);
3367 break;
3368 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndUnmodified:
3369 EXPECT_NE(error, AudioProcessing::kNoError);
3370 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3371 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3372 EXPECT_EQ(output_block.channels()[ch][i],
3373 ch + i * output_num_channels - kUnlikelyOffset);
3374 }
3375 }
3376 break;
3377 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndSilence:
3378 EXPECT_NE(error, AudioProcessing::kNoError);
3379 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3380 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3381 EXPECT_EQ(output_block.channels()[ch][i], 0);
3382 }
3383 }
3384 break;
3385 case ApmFormatHandlingTestParams::ExpectedOutput::
3386 kErrorAndCopyOfFirstChannel:
3387 EXPECT_NE(error, AudioProcessing::kNoError);
3388 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3389 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3390 EXPECT_EQ(output_block.channels()[ch][i],
3391 input_block.channels()[0][i]);
3392 }
3393 }
3394 break;
3395 case ApmFormatHandlingTestParams::ExpectedOutput::kErrorAndExactCopy:
3396 EXPECT_NE(error, AudioProcessing::kNoError);
3397 for (size_t ch = 0; ch < output_num_channels; ++ch) {
3398 for (size_t i = 0; i < output_samples_per_channel; ++i) {
3399 EXPECT_EQ(output_block.channels()[ch][i],
3400 input_block.channels()[ch][i]);
3401 }
3402 }
3403 break;
3404 }
3405}
3406
3407TEST(ApmAnalyzeReverseStreamFormatTest, AnalyzeReverseStream) {
3408 for (auto&& [input_config, expect_error] :
3409 {std::tuple(StreamConfig(16000, 2), /*expect_error=*/false),
3410 std::tuple(StreamConfig(8000, 1), /*expect_error=*/false),
3411 std::tuple(StreamConfig(384000, 1), /*expect_error=*/false),
3412 std::tuple(StreamConfig(7900, 1), /*expect_error=*/true),
3413 std::tuple(StreamConfig(390000, 1), /*expect_error=*/true),
3414 std::tuple(StreamConfig(16000, 0), /*expect_error=*/true),
3415 std::tuple(StreamConfig(-16000, 0), /*expect_error=*/true)}) {
3416 SCOPED_TRACE(::testing::Message()
3417 << "sample_rate_hz=" << input_config.sample_rate_hz()
3418 << " num_channels=" << input_config.num_channels());
3419
3420 // Set up input data.
3421 ChannelBuffer<float> input_block(
3422 std::abs(input_config.sample_rate_hz()) / 100,
3423 input_config.num_channels());
3424
3425 // Call APM.
3426 rtc::scoped_refptr<AudioProcessing> ap =
3427 AudioProcessingBuilderForTesting().Create();
3428 int error = ap->AnalyzeReverseStream(input_block.channels(), input_config);
3429
3430 // Check output.
3431 if (expect_error) {
3432 EXPECT_NE(error, AudioProcessing::kNoError);
3433 } else {
3434 EXPECT_EQ(error, AudioProcessing::kNoError);
3435 }
3436 }
3437}
3438
andrew@webrtc.org27c69802014-02-18 20:24:563439} // namespace webrtc