blob: 5023bab6175b10ecdebaa3bc955af74bbc1b2de5 [file] [log] [blame]
alessiob3ec96df2017-05-22 06:57:06 -07001/*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
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 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "modules/audio_processing/gain_controller2.h"
12
Alessio Bazzica270f7b52017-10-13 11:05:17 +020013#include <algorithm>
Alessio Bazzica980c4602021-04-14 19:09:17 +020014#include <cmath>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020015#include <memory>
Alessio Bazzica6ee97342021-09-27 17:06:40 +020016#include <numeric>
Alessio Bazzica38901042021-10-14 12:14:21 +020017#include <tuple>
alessiob3ec96df2017-05-22 06:57:06 -070018
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "api/array_view.h"
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010020#include "modules/audio_processing/agc2/agc2_testing_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "modules/audio_processing/audio_buffer.h"
Alex Loiko5e784612018-11-01 14:51:56 +010022#include "modules/audio_processing/test/audio_buffer_tools.h"
23#include "modules/audio_processing/test/bitexactness_tools.h"
Alessio Bazzica270f7b52017-10-13 11:05:17 +020024#include "rtc_base/checks.h"
Hanna Silend7cfbe32022-11-02 19:12:20 +010025#include "test/gmock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "test/gtest.h"
alessiob3ec96df2017-05-22 06:57:06 -070027
28namespace webrtc {
29namespace test {
alessiob3ec96df2017-05-22 06:57:06 -070030namespace {
31
Hanna Silend7cfbe32022-11-02 19:12:20 +010032using ::testing::Eq;
33using ::testing::Optional;
34
Alessio Bazzica38901042021-10-14 12:14:21 +020035using Agc2Config = AudioProcessing::Config::GainController2;
Hanna Silena6574902022-11-30 16:59:05 +010036using InputVolumeControllerConfig = InputVolumeController::Config;
Alessio Bazzica38901042021-10-14 12:14:21 +020037
Alessio Bazzica6ee97342021-09-27 17:06:40 +020038// Sets all the samples in `ab` to `value`.
39void SetAudioBufferSamples(float value, AudioBuffer& ab) {
40 for (size_t k = 0; k < ab.num_channels(); ++k) {
41 std::fill(ab.channels()[k], ab.channels()[k] + ab.num_frames(), value);
alessiob3ec96df2017-05-22 06:57:06 -070042 }
43}
44
Alessio Bazzica6ee97342021-09-27 17:06:40 +020045float RunAgc2WithConstantInput(GainController2& agc2,
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010046 float input_level,
Alessio Bazzica6ee97342021-09-27 17:06:40 +020047 int num_frames,
Hanna Silend7cfbe32022-11-02 19:12:20 +010048 int sample_rate_hz,
49 int num_channels = 1,
50 int applied_initial_volume = 0) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +020051 const int num_samples = rtc::CheckedDivExact(sample_rate_hz, 100);
Hanna Silend7cfbe32022-11-02 19:12:20 +010052 AudioBuffer ab(sample_rate_hz, num_channels, sample_rate_hz, num_channels,
53 sample_rate_hz, num_channels);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010054
55 // Give time to the level estimator to converge.
Alessio Bazzica6ee97342021-09-27 17:06:40 +020056 for (int i = 0; i < num_frames + 1; ++i) {
57 SetAudioBufferSamples(input_level, ab);
Hanna Silen597a2ba2022-12-14 12:48:37 +010058 const auto applied_volume = agc2.recommended_input_volume();
59 agc2.Analyze(applied_volume.value_or(applied_initial_volume), ab);
60
Alessio Bazzicafcf1af32022-09-07 17:14:26 +020061 agc2.Process(/*speech_probability=*/absl::nullopt,
62 /*input_volume_changed=*/false, &ab);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010063 }
64
65 // Return the last sample from the last processed frame.
Per Ã…hgrend47941e2019-08-22 11:51:13 +020066 return ab.channels()[0][num_samples - 1];
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010067}
68
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010069std::unique_ptr<GainController2> CreateAgc2FixedDigitalMode(
70 float fixed_gain_db,
Alessio Bazzica6ee97342021-09-27 17:06:40 +020071 int sample_rate_hz) {
Alessio Bazzica38901042021-10-14 12:14:21 +020072 Agc2Config config;
73 config.adaptive_digital.enabled = false;
74 config.fixed_digital.gain_db = fixed_gain_db;
75 EXPECT_TRUE(GainController2::Validate(config));
Hanna Silena6574902022-11-30 16:59:05 +010076 return std::make_unique<GainController2>(
77 config, InputVolumeControllerConfig{}, sample_rate_hz,
78 /*num_channels=*/1,
79 /*use_internal_vad=*/true);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +010080}
81
Hanna Silena6574902022-11-30 16:59:05 +010082constexpr InputVolumeControllerConfig kTestInputVolumeControllerConfig{
83 .clipped_level_min = 20,
84 .clipped_level_step = 30,
85 .clipped_ratio_threshold = 0.4,
86 .clipped_wait_frames = 50,
87 .enable_clipping_predictor = true,
88 .target_range_max_dbfs = -6,
89 .target_range_min_dbfs = -70,
90 .update_input_volume_wait_frames = 100,
91 .speech_probability_threshold = 0.9,
92 .speech_ratio_threshold = 1,
93};
94
alessiob3ec96df2017-05-22 06:57:06 -070095} // namespace
96
Alessio Bazzica0c83e152020-10-14 12:49:54 +020097TEST(GainController2, CheckDefaultConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +020098 Agc2Config config;
Alessio Bazzica270f7b52017-10-13 11:05:17 +020099 EXPECT_TRUE(GainController2::Validate(config));
alessiob3ec96df2017-05-22 06:57:06 -0700100}
101
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200102TEST(GainController2, CheckFixedDigitalConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200103 Agc2Config config;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200104 // Attenuation is not allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200105 config.fixed_digital.gain_db = -5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200106 EXPECT_FALSE(GainController2::Validate(config));
107 // No gain is allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200108 config.fixed_digital.gain_db = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200109 EXPECT_TRUE(GainController2::Validate(config));
110 // Positive gain is allowed.
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200111 config.fixed_digital.gain_db = 15.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200112 EXPECT_TRUE(GainController2::Validate(config));
113}
alessiob3ec96df2017-05-22 06:57:06 -0700114
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200115TEST(GainController2, CheckHeadroomDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200116 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200117 config.adaptive_digital.headroom_db = -1.0f;
118 EXPECT_FALSE(GainController2::Validate(config));
119 config.adaptive_digital.headroom_db = 0.0f;
120 EXPECT_TRUE(GainController2::Validate(config));
121 config.adaptive_digital.headroom_db = 5.0f;
122 EXPECT_TRUE(GainController2::Validate(config));
123}
124
125TEST(GainController2, CheckMaxGainDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200126 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200127 config.adaptive_digital.max_gain_db = -1.0f;
128 EXPECT_FALSE(GainController2::Validate(config));
129 config.adaptive_digital.max_gain_db = 0.0f;
130 EXPECT_FALSE(GainController2::Validate(config));
131 config.adaptive_digital.max_gain_db = 5.0f;
132 EXPECT_TRUE(GainController2::Validate(config));
133}
134
135TEST(GainController2, CheckInitialGainDb) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200136 Agc2Config config;
Alessio Bazzicaa850e6c2021-10-04 13:35:55 +0200137 config.adaptive_digital.initial_gain_db = -1.0f;
138 EXPECT_FALSE(GainController2::Validate(config));
139 config.adaptive_digital.initial_gain_db = 0.0f;
140 EXPECT_TRUE(GainController2::Validate(config));
141 config.adaptive_digital.initial_gain_db = 5.0f;
142 EXPECT_TRUE(GainController2::Validate(config));
143}
144
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200145TEST(GainController2, CheckAdaptiveDigitalMaxGainChangeSpeedConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200146 Agc2Config config;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200147 config.adaptive_digital.max_gain_change_db_per_second = -1.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200148 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200149 config.adaptive_digital.max_gain_change_db_per_second = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200150 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200151 config.adaptive_digital.max_gain_change_db_per_second = 5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200152 EXPECT_TRUE(GainController2::Validate(config));
153}
154
155TEST(GainController2, CheckAdaptiveDigitalMaxOutputNoiseLevelConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200156 Agc2Config config;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200157 config.adaptive_digital.max_output_noise_level_dbfs = 5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200158 EXPECT_FALSE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200159 config.adaptive_digital.max_output_noise_level_dbfs = 0.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200160 EXPECT_TRUE(GainController2::Validate(config));
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200161 config.adaptive_digital.max_output_noise_level_dbfs = -5.0f;
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200162 EXPECT_TRUE(GainController2::Validate(config));
163}
164
Hanna Silend7cfbe32022-11-02 19:12:20 +0100165TEST(GainController2,
166 CheckGetRecommendedInputVolumeWhenInputVolumeControllerNotEnabled) {
167 constexpr float kHighInputLevel = 32767.0f;
168 constexpr float kLowInputLevel = 1000.0f;
169 constexpr int kInitialInputVolume = 100;
170 constexpr int kNumChannels = 2;
171 constexpr int kNumFrames = 5;
172 constexpr int kSampleRateHz = 16000;
173
174 Agc2Config config;
175 config.input_volume_controller.enabled = false;
Hanna Silen27fed452022-11-22 15:00:58 +0100176
Hanna Silena6574902022-11-30 16:59:05 +0100177 auto gain_controller = std::make_unique<GainController2>(
178 config, InputVolumeControllerConfig{}, kSampleRateHz, kNumChannels,
179 /*use_internal_vad=*/true);
180
Hanna Silen597a2ba2022-12-14 12:48:37 +0100181 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100182
183 // Run AGC for a signal with no clipping or detected speech.
184 RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
185 kSampleRateHz, kNumChannels, kInitialInputVolume);
186
Hanna Silen597a2ba2022-12-14 12:48:37 +0100187 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100188
189 // Run AGC for a signal with clipping.
190 RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
191 kSampleRateHz, kNumChannels, kInitialInputVolume);
192
Hanna Silen597a2ba2022-12-14 12:48:37 +0100193 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100194}
195
196TEST(
197 GainController2,
198 CheckGetRecommendedInputVolumeWhenInputVolumeControllerNotEnabledAndSpecificConfigUsed) {
199 constexpr float kHighInputLevel = 32767.0f;
200 constexpr float kLowInputLevel = 1000.0f;
201 constexpr int kInitialInputVolume = 100;
202 constexpr int kNumChannels = 2;
203 constexpr int kNumFrames = 5;
204 constexpr int kSampleRateHz = 16000;
205
206 Agc2Config config;
207 config.input_volume_controller.enabled = false;
208
209 auto gain_controller = std::make_unique<GainController2>(
210 config, kTestInputVolumeControllerConfig, kSampleRateHz, kNumChannels,
211 /*use_internal_vad=*/true);
Hanna Silend7cfbe32022-11-02 19:12:20 +0100212
Hanna Silen597a2ba2022-12-14 12:48:37 +0100213 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100214
215 // Run AGC for a signal with no clipping or detected speech.
216 RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
217 kSampleRateHz, kNumChannels, kInitialInputVolume);
218
Hanna Silen597a2ba2022-12-14 12:48:37 +0100219 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100220
221 // Run AGC for a signal with clipping.
222 RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
223 kSampleRateHz, kNumChannels, kInitialInputVolume);
224
Hanna Silen597a2ba2022-12-14 12:48:37 +0100225 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100226}
227
228TEST(GainController2,
229 CheckGetRecommendedInputVolumeWhenInputVolumeControllerEnabled) {
230 constexpr float kHighInputLevel = 32767.0f;
231 constexpr float kLowInputLevel = 1000.0f;
232 constexpr int kInitialInputVolume = 100;
233 constexpr int kNumChannels = 2;
234 constexpr int kNumFrames = 5;
235 constexpr int kSampleRateHz = 16000;
236
237 Agc2Config config;
238 config.input_volume_controller.enabled = true;
Hanna Silen27fed452022-11-22 15:00:58 +0100239 config.adaptive_digital.enabled = true;
240
Hanna Silena6574902022-11-30 16:59:05 +0100241 auto gain_controller = std::make_unique<GainController2>(
242 config, InputVolumeControllerConfig{}, kSampleRateHz, kNumChannels,
243 /*use_internal_vad=*/true);
244
Hanna Silen597a2ba2022-12-14 12:48:37 +0100245 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100246
247 // Run AGC for a signal with no clipping or detected speech.
248 RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
249 kSampleRateHz, kNumChannels, kInitialInputVolume);
250
Hanna Silen597a2ba2022-12-14 12:48:37 +0100251 EXPECT_TRUE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100252
253 // Run AGC for a signal with clipping.
254 RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
255 kSampleRateHz, kNumChannels, kInitialInputVolume);
256
Hanna Silen597a2ba2022-12-14 12:48:37 +0100257 EXPECT_TRUE(gain_controller->recommended_input_volume().has_value());
Hanna Silena6574902022-11-30 16:59:05 +0100258}
259
260TEST(
261 GainController2,
262 CheckGetRecommendedInputVolumeWhenInputVolumeControllerEnabledAndSpecificConfigUsed) {
263 constexpr float kHighInputLevel = 32767.0f;
264 constexpr float kLowInputLevel = 1000.0f;
265 constexpr int kInitialInputVolume = 100;
266 constexpr int kNumChannels = 2;
267 constexpr int kNumFrames = 5;
268 constexpr int kSampleRateHz = 16000;
269
270 Agc2Config config;
271 config.input_volume_controller.enabled = true;
272 config.adaptive_digital.enabled = true;
273
274 auto gain_controller = std::make_unique<GainController2>(
275 config, kTestInputVolumeControllerConfig, kSampleRateHz, kNumChannels,
276 /*use_internal_vad=*/true);
Hanna Silend7cfbe32022-11-02 19:12:20 +0100277
Hanna Silen597a2ba2022-12-14 12:48:37 +0100278 EXPECT_FALSE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100279
280 // Run AGC for a signal with no clipping or detected speech.
281 RunAgc2WithConstantInput(*gain_controller, kLowInputLevel, kNumFrames,
282 kSampleRateHz, kNumChannels, kInitialInputVolume);
283
Hanna Silen597a2ba2022-12-14 12:48:37 +0100284 EXPECT_TRUE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100285
286 // Run AGC for a signal with clipping.
287 RunAgc2WithConstantInput(*gain_controller, kHighInputLevel, kNumFrames,
288 kSampleRateHz, kNumChannels, kInitialInputVolume);
289
Hanna Silen597a2ba2022-12-14 12:48:37 +0100290 EXPECT_TRUE(gain_controller->recommended_input_volume().has_value());
Hanna Silend7cfbe32022-11-02 19:12:20 +0100291}
292
Alessio Bazzica0c83e152020-10-14 12:49:54 +0200293// Checks that the default config is applied.
294TEST(GainController2, ApplyDefaultConfig) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200295 auto gain_controller2 = std::make_unique<GainController2>(
Hanna Silena6574902022-11-30 16:59:05 +0100296 Agc2Config{}, InputVolumeControllerConfig{},
297 /*sample_rate_hz=*/16000, /*num_channels=*/2,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200298 /*use_internal_vad=*/true);
Alessio Bazzica38901042021-10-14 12:14:21 +0200299 EXPECT_TRUE(gain_controller2.get());
alessiob3ec96df2017-05-22 06:57:06 -0700300}
301
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100302TEST(GainController2FixedDigital, GainShouldChangeOnSetGain) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200303 constexpr float kInputLevel = 1000.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100304 constexpr size_t kNumFrames = 5;
305 constexpr size_t kSampleRateHz = 8000;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200306 constexpr float kGain0Db = 0.0f;
307 constexpr float kGain20Db = 20.0f;
Alessio Bazzica270f7b52017-10-13 11:05:17 +0200308
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100309 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGain0Db, kSampleRateHz);
310
311 // Signal level is unchanged with 0 db gain.
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200312 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel, kNumFrames,
313 kSampleRateHz),
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100314 kInputLevel);
315
316 // +20 db should increase signal by a factor of 10.
Alessio Bazzica38901042021-10-14 12:14:21 +0200317 agc2_fixed->SetFixedGainDb(kGain20Db);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200318 EXPECT_FLOAT_EQ(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel, kNumFrames,
319 kSampleRateHz),
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100320 kInputLevel * 10);
alessiob3ec96df2017-05-22 06:57:06 -0700321}
322
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100323TEST(GainController2FixedDigital, ChangeFixedGainShouldBeFastAndTimeInvariant) {
324 // Number of frames required for the fixed gain controller to adapt on the
325 // input signal when the gain changes.
326 constexpr size_t kNumFrames = 5;
Alex Loiko5e784612018-11-01 14:51:56 +0100327
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200328 constexpr float kInputLevel = 1000.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100329 constexpr size_t kSampleRateHz = 8000;
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200330 constexpr float kGainDbLow = 0.0f;
331 constexpr float kGainDbHigh = 25.0f;
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100332 static_assert(kGainDbLow < kGainDbHigh, "");
Alex Loiko5e784612018-11-01 14:51:56 +0100333
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100334 auto agc2_fixed = CreateAgc2FixedDigitalMode(kGainDbLow, kSampleRateHz);
335
336 // Start with a lower gain.
337 const float output_level_pre = RunAgc2WithConstantInput(
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200338 *agc2_fixed, kInputLevel, kNumFrames, kSampleRateHz);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100339
340 // Increase gain.
Alessio Bazzica38901042021-10-14 12:14:21 +0200341 agc2_fixed->SetFixedGainDb(kGainDbHigh);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200342 static_cast<void>(RunAgc2WithConstantInput(*agc2_fixed, kInputLevel,
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100343 kNumFrames, kSampleRateHz));
344
345 // Back to the lower gain.
Alessio Bazzica38901042021-10-14 12:14:21 +0200346 agc2_fixed->SetFixedGainDb(kGainDbLow);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100347 const float output_level_post = RunAgc2WithConstantInput(
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200348 *agc2_fixed, kInputLevel, kNumFrames, kSampleRateHz);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100349
350 EXPECT_EQ(output_level_pre, output_level_post);
351}
352
Alessio Bazzica38901042021-10-14 12:14:21 +0200353class FixedDigitalTest
354 : public ::testing::TestWithParam<std::tuple<float, float, int, bool>> {
355 protected:
356 float gain_db_min() const { return std::get<0>(GetParam()); }
357 float gain_db_max() const { return std::get<1>(GetParam()); }
358 int sample_rate_hz() const { return std::get<2>(GetParam()); }
359 bool saturation_expected() const { return std::get<3>(GetParam()); }
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100360};
361
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100362TEST_P(FixedDigitalTest, CheckSaturationBehaviorWithLimiter) {
Alessio Bazzica38901042021-10-14 12:14:21 +0200363 for (const float gain_db : test::LinSpace(gain_db_min(), gain_db_max(), 10)) {
364 SCOPED_TRACE(gain_db);
365 auto agc2_fixed = CreateAgc2FixedDigitalMode(gain_db, sample_rate_hz());
366 const float processed_sample =
367 RunAgc2WithConstantInput(*agc2_fixed, /*input_level=*/32767.0f,
368 /*num_frames=*/5, sample_rate_hz());
369 if (saturation_expected()) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200370 EXPECT_FLOAT_EQ(processed_sample, 32767.0f);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100371 } else {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200372 EXPECT_LT(processed_sample, 32767.0f);
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100373 }
Alex Loiko5e784612018-11-01 14:51:56 +0100374 }
Alex Loiko5e784612018-11-01 14:51:56 +0100375}
376
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100377static_assert(test::kLimiterMaxInputLevelDbFs < 10, "");
Mirko Bonadeic84f6612019-01-31 12:20:57 +0100378INSTANTIATE_TEST_SUITE_P(
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100379 GainController2,
380 FixedDigitalTest,
381 ::testing::Values(
Artem Titovcfea2182021-08-10 01:22:31 +0200382 // When gain < `test::kLimiterMaxInputLevelDbFs`, the limiter will not
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100383 // saturate the signal (at any sample rate).
Alessio Bazzica38901042021-10-14 12:14:21 +0200384 std::make_tuple(0.1f,
385 test::kLimiterMaxInputLevelDbFs - 0.01f,
386 8000,
387 false),
388 std::make_tuple(0.1,
389 test::kLimiterMaxInputLevelDbFs - 0.01f,
390 48000,
391 false),
Artem Titovcfea2182021-08-10 01:22:31 +0200392 // When gain > `test::kLimiterMaxInputLevelDbFs`, the limiter will
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100393 // saturate the signal (at any sample rate).
Alessio Bazzica38901042021-10-14 12:14:21 +0200394 std::make_tuple(test::kLimiterMaxInputLevelDbFs + 0.01f,
395 10.0f,
396 8000,
397 true),
398 std::make_tuple(test::kLimiterMaxInputLevelDbFs + 0.01f,
399 10.0f,
400 48000,
401 true)));
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100402
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200403// Processes a test audio file and checks that the gain applied at the end of
404// the recording is close to the expected value.
405TEST(GainController2, CheckFinalGainWithAdaptiveDigitalController) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200406 constexpr int kSampleRateHz = AudioProcessing::kSampleRate48kHz;
407 constexpr int kStereo = 2;
Alessio Bazzica38901042021-10-14 12:14:21 +0200408
409 // Create AGC2 enabling only the adaptive digital controller.
410 Agc2Config config;
411 config.fixed_digital.gain_db = 0.0f;
412 config.adaptive_digital.enabled = true;
Hanna Silena6574902022-11-30 16:59:05 +0100413 GainController2 agc2(config, /*input_volume_controller_config=*/{},
414 kSampleRateHz, kStereo,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200415 /*use_internal_vad=*/true);
Alessio Bazzica38901042021-10-14 12:14:21 +0200416
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200417 test::InputAudioFile input_file(
418 test::GetApmCaptureTestVectorFileName(kSampleRateHz),
419 /*loop_at_end=*/true);
Henrik Lundin64253a92022-02-04 09:02:48 +0000420 const StreamConfig stream_config(kSampleRateHz, kStereo);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200421
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200422 // Init buffers.
423 constexpr int kFrameDurationMs = 10;
424 std::vector<float> frame(kStereo * stream_config.num_frames());
425 AudioBuffer audio_buffer(kSampleRateHz, kStereo, kSampleRateHz, kStereo,
426 kSampleRateHz, kStereo);
427
428 // Simulate.
429 constexpr float kGainDb = -6.0f;
430 const float gain = std::pow(10.0f, kGainDb / 20.0f);
431 constexpr int kDurationMs = 10000;
432 constexpr int kNumFramesToProcess = kDurationMs / kFrameDurationMs;
433 for (int i = 0; i < kNumFramesToProcess; ++i) {
434 ReadFloatSamplesFromStereoFile(stream_config.num_frames(),
435 stream_config.num_channels(), &input_file,
436 frame);
437 // Apply a fixed gain to the input audio.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200438 for (float& x : frame) {
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200439 x *= gain;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200440 }
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200441 test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200442 agc2.Process(/*speech_probability=*/absl::nullopt,
443 /*input_volume_changed=*/false, &audio_buffer);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200444 }
445
446 // Estimate the applied gain by processing a probing frame.
447 SetAudioBufferSamples(/*value=*/1.0f, audio_buffer);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200448 agc2.Process(/*speech_probability=*/absl::nullopt,
449 /*input_volume_changed=*/false, &audio_buffer);
Alessio Bazzica6ee97342021-09-27 17:06:40 +0200450 const float applied_gain_db =
451 20.0f * std::log10(audio_buffer.channels_const()[0][0]);
452
453 constexpr float kExpectedGainDb = 5.6f;
454 constexpr float kToleranceDb = 0.3f;
455 EXPECT_NEAR(applied_gain_db, kExpectedGainDb, kToleranceDb);
Alex Loiko5e784612018-11-01 14:51:56 +0100456}
Alessio Bazzica3e4c77f2018-11-01 21:31:38 +0100457
Alessio Bazzica40b5bd72023-01-16 20:19:48 +0100458#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
459// Checks that `GainController2` crashes in debug mode if it runs its internal
460// VAD and the speech probability values are provided by the caller.
461TEST(GainController2DeathTest,
462 DebugCrashIfUseInternalVadAndSpeechProbabilityGiven) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200463 constexpr int kSampleRateHz = AudioProcessing::kSampleRate48kHz;
464 constexpr int kStereo = 2;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200465 AudioBuffer audio_buffer(kSampleRateHz, kStereo, kSampleRateHz, kStereo,
466 kSampleRateHz, kStereo);
Alessio Bazzica40b5bd72023-01-16 20:19:48 +0100467 // Create AGC2 so that the interval VAD is also created.
468 GainController2 agc2(/*config=*/{.adaptive_digital = {.enabled = true}},
469 /*input_volume_controller_config=*/{}, kSampleRateHz,
470 kStereo,
471 /*use_internal_vad=*/true);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200472
Alessio Bazzica40b5bd72023-01-16 20:19:48 +0100473 EXPECT_DEATH(agc2.Process(/*speech_probability=*/0.123f,
474 /*input_volume_changed=*/false, &audio_buffer),
475 "");
Hanna Silen0c1ad292022-06-16 16:35:45 +0200476}
Alessio Bazzica40b5bd72023-01-16 20:19:48 +0100477#endif
Hanna Silen0c1ad292022-06-16 16:35:45 +0200478
479// Processes a test audio file and checks that the injected speech probability
480// is not ignored when the internal VAD is not used.
481TEST(GainController2,
482 CheckInjectedVadProbabilityUsedWithAdaptiveDigitalController) {
483 constexpr int kSampleRateHz = AudioProcessing::kSampleRate48kHz;
484 constexpr int kStereo = 2;
485
486 // Create AGC2 enabling only the adaptive digital controller.
487 Agc2Config config;
488 config.fixed_digital.gain_db = 0.0f;
489 config.adaptive_digital.enabled = true;
Hanna Silena6574902022-11-30 16:59:05 +0100490 GainController2 agc2(config, /*input_volume_controller_config=*/{},
491 kSampleRateHz, kStereo,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200492 /*use_internal_vad=*/false);
Hanna Silena6574902022-11-30 16:59:05 +0100493 GainController2 agc2_reference(config, /*input_volume_controller_config=*/{},
494 kSampleRateHz, kStereo,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200495 /*use_internal_vad=*/true);
496
497 test::InputAudioFile input_file(
498 test::GetApmCaptureTestVectorFileName(kSampleRateHz),
499 /*loop_at_end=*/true);
500 const StreamConfig stream_config(kSampleRateHz, kStereo);
501
502 // Init buffers.
503 constexpr int kFrameDurationMs = 10;
504 std::vector<float> frame(kStereo * stream_config.num_frames());
505 AudioBuffer audio_buffer(kSampleRateHz, kStereo, kSampleRateHz, kStereo,
506 kSampleRateHz, kStereo);
507 AudioBuffer audio_buffer_reference(kSampleRateHz, kStereo, kSampleRateHz,
508 kStereo, kSampleRateHz, kStereo);
509 // Simulate.
510 constexpr float kGainDb = -6.0f;
511 const float gain = std::pow(10.0f, kGainDb / 20.0f);
512 constexpr int kDurationMs = 10000;
513 constexpr int kNumFramesToProcess = kDurationMs / kFrameDurationMs;
514 constexpr float kSpeechProbabilities[] = {1.0f, 0.3f};
515 constexpr float kEpsilon = 0.0001f;
516 bool all_samples_zero = true;
517 bool all_samples_equal = true;
518 for (int i = 0, j = 0; i < kNumFramesToProcess; ++i, j = 1 - j) {
519 ReadFloatSamplesFromStereoFile(stream_config.num_frames(),
520 stream_config.num_channels(), &input_file,
521 frame);
522 // Apply a fixed gain to the input audio.
523 for (float& x : frame) {
524 x *= gain;
525 }
526 test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200527 agc2.Process(kSpeechProbabilities[j], /*input_volume_changed=*/false,
528 &audio_buffer);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200529 test::CopyVectorToAudioBuffer(stream_config, frame,
530 &audio_buffer_reference);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200531 agc2_reference.Process(/*speech_probability=*/absl::nullopt,
532 /*input_volume_changed=*/false,
533 &audio_buffer_reference);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200534 // Check the output buffers.
535 for (int i = 0; i < kStereo; ++i) {
536 for (int j = 0; j < static_cast<int>(audio_buffer.num_frames()); ++j) {
537 all_samples_zero &=
538 fabs(audio_buffer.channels_const()[i][j]) < kEpsilon;
539 all_samples_equal &=
540 fabs(audio_buffer.channels_const()[i][j] -
541 audio_buffer_reference.channels_const()[i][j]) < kEpsilon;
542 }
543 }
544 }
545 EXPECT_FALSE(all_samples_zero);
546 EXPECT_FALSE(all_samples_equal);
547}
548
549// Processes a test audio file and checks that the output is equal when
550// an injected speech probability from `VoiceActivityDetectorWrapper` and
551// the speech probability computed by the internal VAD are the same.
552TEST(GainController2,
553 CheckEqualResultFromInjectedVadProbabilityWithAdaptiveDigitalController) {
554 constexpr int kSampleRateHz = AudioProcessing::kSampleRate48kHz;
555 constexpr int kStereo = 2;
556
557 // Create AGC2 enabling only the adaptive digital controller.
558 Agc2Config config;
559 config.fixed_digital.gain_db = 0.0f;
560 config.adaptive_digital.enabled = true;
Hanna Silena6574902022-11-30 16:59:05 +0100561 GainController2 agc2(config, /*input_volume_controller_config=*/{},
562 kSampleRateHz, kStereo,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200563 /*use_internal_vad=*/false);
Hanna Silena6574902022-11-30 16:59:05 +0100564 GainController2 agc2_reference(config, /*input_volume_controller_config=*/{},
565 kSampleRateHz, kStereo,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200566 /*use_internal_vad=*/true);
Alessio Bazzicadfba28e2022-12-09 10:02:41 +0100567 VoiceActivityDetectorWrapper vad(GetAvailableCpuFeatures(), kSampleRateHz);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200568 test::InputAudioFile input_file(
569 test::GetApmCaptureTestVectorFileName(kSampleRateHz),
570 /*loop_at_end=*/true);
571 const StreamConfig stream_config(kSampleRateHz, kStereo);
572
573 // Init buffers.
574 constexpr int kFrameDurationMs = 10;
575 std::vector<float> frame(kStereo * stream_config.num_frames());
576 AudioBuffer audio_buffer(kSampleRateHz, kStereo, kSampleRateHz, kStereo,
577 kSampleRateHz, kStereo);
578 AudioBuffer audio_buffer_reference(kSampleRateHz, kStereo, kSampleRateHz,
579 kStereo, kSampleRateHz, kStereo);
580
581 // Simulate.
582 constexpr float kGainDb = -6.0f;
583 const float gain = std::pow(10.0f, kGainDb / 20.0f);
584 constexpr int kDurationMs = 10000;
585 constexpr int kNumFramesToProcess = kDurationMs / kFrameDurationMs;
586 for (int i = 0; i < kNumFramesToProcess; ++i) {
587 ReadFloatSamplesFromStereoFile(stream_config.num_frames(),
588 stream_config.num_channels(), &input_file,
589 frame);
590 // Apply a fixed gain to the input audio.
591 for (float& x : frame) {
592 x *= gain;
593 }
594 test::CopyVectorToAudioBuffer(stream_config, frame,
595 &audio_buffer_reference);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200596 agc2_reference.Process(absl::nullopt, /*input_volume_changed=*/false,
597 &audio_buffer_reference);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200598 test::CopyVectorToAudioBuffer(stream_config, frame, &audio_buffer);
Alessio Bazzicafcf1af32022-09-07 17:14:26 +0200599 float speech_probability = vad.Analyze(AudioFrameView<const float>(
600 audio_buffer.channels(), audio_buffer.num_channels(),
601 audio_buffer.num_frames()));
602 agc2.Process(speech_probability, /*input_volume_changed=*/false,
Hanna Silen0c1ad292022-06-16 16:35:45 +0200603 &audio_buffer);
604 // Check the output buffer.
605 for (int i = 0; i < kStereo; ++i) {
606 for (int j = 0; j < static_cast<int>(audio_buffer.num_frames()); ++j) {
607 EXPECT_FLOAT_EQ(audio_buffer.channels_const()[i][j],
608 audio_buffer_reference.channels_const()[i][j]);
609 }
610 }
611 }
612}
613
alessiob3ec96df2017-05-22 06:57:06 -0700614} // namespace test
615} // namespace webrtc