1 /*
2  *  Copyright (c) 2021 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 #include "modules/audio_processing/capture_levels_adjuster/capture_levels_adjuster.h"
11 
12 #include <algorithm>
13 #include <tuple>
14 
15 #include "modules/audio_processing/test/audio_buffer_tools.h"
16 #include "rtc_base/strings/string_builder.h"
17 #include "test/gtest.h"
18 
19 namespace webrtc {
20 namespace {
21 
SampleValueForChannel(int channel)22 float SampleValueForChannel(int channel) {
23   constexpr float kSampleBaseValue = 100.f;
24   constexpr float kSampleChannelOffset = 1.f;
25   return kSampleBaseValue + channel * kSampleChannelOffset;
26 }
27 
PopulateBuffer(AudioBuffer & audio_buffer)28 void PopulateBuffer(AudioBuffer& audio_buffer) {
29   for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
30     test::FillBufferChannel(SampleValueForChannel(ch), ch, audio_buffer);
31   }
32 }
33 
ComputeExpectedSignalGainAfterApplyPreLevelAdjustment(bool emulated_analog_mic_gain_enabled,int emulated_analog_mic_gain_level,float pre_gain)34 float ComputeExpectedSignalGainAfterApplyPreLevelAdjustment(
35     bool emulated_analog_mic_gain_enabled,
36     int emulated_analog_mic_gain_level,
37     float pre_gain) {
38   if (!emulated_analog_mic_gain_enabled) {
39     return pre_gain;
40   }
41   return pre_gain * std::min(emulated_analog_mic_gain_level, 255) / 255.f;
42 }
43 
ComputeExpectedSignalGainAfterApplyPostLevelAdjustment(bool emulated_analog_mic_gain_enabled,int emulated_analog_mic_gain_level,float pre_gain,float post_gain)44 float ComputeExpectedSignalGainAfterApplyPostLevelAdjustment(
45     bool emulated_analog_mic_gain_enabled,
46     int emulated_analog_mic_gain_level,
47     float pre_gain,
48     float post_gain) {
49   return post_gain * ComputeExpectedSignalGainAfterApplyPreLevelAdjustment(
50                          emulated_analog_mic_gain_enabled,
51                          emulated_analog_mic_gain_level, pre_gain);
52 }
53 
54 constexpr int kNumFramesToProcess = 10;
55 
56 class CaptureLevelsAdjusterTest
57     : public ::testing::Test,
58       public ::testing::WithParamInterface<
59           std::tuple<int, int, bool, int, float, float>> {
60  protected:
sample_rate_hz() const61   int sample_rate_hz() const { return std::get<0>(GetParam()); }
num_channels() const62   int num_channels() const { return std::get<1>(GetParam()); }
emulated_analog_mic_gain_enabled() const63   bool emulated_analog_mic_gain_enabled() const {
64     return std::get<2>(GetParam());
65   }
emulated_analog_mic_gain_level() const66   int emulated_analog_mic_gain_level() const { return std::get<3>(GetParam()); }
pre_gain() const67   float pre_gain() const { return std::get<4>(GetParam()); }
post_gain() const68   float post_gain() const { return std::get<5>(GetParam()); }
69 };
70 
71 INSTANTIATE_TEST_SUITE_P(
72     CaptureLevelsAdjusterTestSuite,
73     CaptureLevelsAdjusterTest,
74     ::testing::Combine(::testing::Values(16000, 32000, 48000),
75                        ::testing::Values(1, 2, 4),
76                        ::testing::Values(false, true),
77                        ::testing::Values(21, 255),
78                        ::testing::Values(0.1f, 1.f, 4.f),
79                        ::testing::Values(0.1f, 1.f, 4.f)));
80 
TEST_P(CaptureLevelsAdjusterTest,InitialGainIsInstantlyAchieved)81 TEST_P(CaptureLevelsAdjusterTest, InitialGainIsInstantlyAchieved) {
82   CaptureLevelsAdjuster adjuster(emulated_analog_mic_gain_enabled(),
83                                  emulated_analog_mic_gain_level(), pre_gain(),
84                                  post_gain());
85 
86   AudioBuffer audio_buffer(sample_rate_hz(), num_channels(), sample_rate_hz(),
87                            num_channels(), sample_rate_hz(), num_channels());
88 
89   const float expected_signal_gain_after_pre_gain =
90       ComputeExpectedSignalGainAfterApplyPreLevelAdjustment(
91           emulated_analog_mic_gain_enabled(), emulated_analog_mic_gain_level(),
92           pre_gain());
93   const float expected_signal_gain_after_post_level_adjustment =
94       ComputeExpectedSignalGainAfterApplyPostLevelAdjustment(
95           emulated_analog_mic_gain_enabled(), emulated_analog_mic_gain_level(),
96           pre_gain(), post_gain());
97 
98   for (int frame = 0; frame < kNumFramesToProcess; ++frame) {
99     PopulateBuffer(audio_buffer);
100     adjuster.ApplyPreLevelAdjustment(audio_buffer);
101     EXPECT_FLOAT_EQ(adjuster.GetPreAdjustmentGain(),
102                     expected_signal_gain_after_pre_gain);
103 
104     for (int ch = 0; ch < num_channels(); ++ch) {
105       for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
106         EXPECT_FLOAT_EQ(
107             audio_buffer.channels_const()[ch][i],
108             expected_signal_gain_after_pre_gain * SampleValueForChannel(ch));
109       }
110     }
111     adjuster.ApplyPostLevelAdjustment(audio_buffer);
112     for (int ch = 0; ch < num_channels(); ++ch) {
113       for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
114         EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
115                         expected_signal_gain_after_post_level_adjustment *
116                             SampleValueForChannel(ch));
117       }
118     }
119   }
120 }
121 
TEST_P(CaptureLevelsAdjusterTest,NewGainsAreAchieved)122 TEST_P(CaptureLevelsAdjusterTest, NewGainsAreAchieved) {
123   const int lower_emulated_analog_mic_gain_level =
124       emulated_analog_mic_gain_level();
125   const float lower_pre_gain = pre_gain();
126   const float lower_post_gain = post_gain();
127   const int higher_emulated_analog_mic_gain_level =
128       std::min(lower_emulated_analog_mic_gain_level * 2, 255);
129   const float higher_pre_gain = lower_pre_gain * 2.f;
130   const float higher_post_gain = lower_post_gain * 2.f;
131 
132   CaptureLevelsAdjuster adjuster(emulated_analog_mic_gain_enabled(),
133                                  lower_emulated_analog_mic_gain_level,
134                                  lower_pre_gain, lower_post_gain);
135 
136   AudioBuffer audio_buffer(sample_rate_hz(), num_channels(), sample_rate_hz(),
137                            num_channels(), sample_rate_hz(), num_channels());
138 
139   const float expected_signal_gain_after_pre_gain =
140       ComputeExpectedSignalGainAfterApplyPreLevelAdjustment(
141           emulated_analog_mic_gain_enabled(),
142           higher_emulated_analog_mic_gain_level, higher_pre_gain);
143   const float expected_signal_gain_after_post_level_adjustment =
144       ComputeExpectedSignalGainAfterApplyPostLevelAdjustment(
145           emulated_analog_mic_gain_enabled(),
146           higher_emulated_analog_mic_gain_level, higher_pre_gain,
147           higher_post_gain);
148 
149   adjuster.SetPreGain(higher_pre_gain);
150   adjuster.SetPostGain(higher_post_gain);
151   adjuster.SetAnalogMicGainLevel(higher_emulated_analog_mic_gain_level);
152 
153   PopulateBuffer(audio_buffer);
154   adjuster.ApplyPreLevelAdjustment(audio_buffer);
155   adjuster.ApplyPostLevelAdjustment(audio_buffer);
156   EXPECT_EQ(adjuster.GetAnalogMicGainLevel(),
157             higher_emulated_analog_mic_gain_level);
158 
159   for (int frame = 1; frame < kNumFramesToProcess; ++frame) {
160     PopulateBuffer(audio_buffer);
161     adjuster.ApplyPreLevelAdjustment(audio_buffer);
162     EXPECT_FLOAT_EQ(adjuster.GetPreAdjustmentGain(),
163                     expected_signal_gain_after_pre_gain);
164     for (int ch = 0; ch < num_channels(); ++ch) {
165       for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
166         EXPECT_FLOAT_EQ(
167             audio_buffer.channels_const()[ch][i],
168             expected_signal_gain_after_pre_gain * SampleValueForChannel(ch));
169       }
170     }
171 
172     adjuster.ApplyPostLevelAdjustment(audio_buffer);
173     for (int ch = 0; ch < num_channels(); ++ch) {
174       for (size_t i = 0; i < audio_buffer.num_frames(); ++i) {
175         EXPECT_FLOAT_EQ(audio_buffer.channels_const()[ch][i],
176                         expected_signal_gain_after_post_level_adjustment *
177                             SampleValueForChannel(ch));
178       }
179     }
180 
181     EXPECT_EQ(adjuster.GetAnalogMicGainLevel(),
182               higher_emulated_analog_mic_gain_level);
183   }
184 }
185 
186 }  // namespace
187 }  // namespace webrtc
188