Add APM test of pre-amplifier gain
This tests that both the ApplyConfig() and SetRuntimeSetting() route of
APM configuration correctly induce the pre-amplifier gain effect in APM.
Bug: webrtc:11045
Change-Id: Iddaa1c19487c6f68ed6eb1be6913ec2dfd284b04
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158083
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29607}
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 5f2ce87..c7d325c 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -16,6 +16,7 @@
#include <cmath>
#include <limits>
#include <memory>
+#include <numeric>
#include <queue>
#include "absl/flags/flag.h"
@@ -172,6 +173,18 @@
return true;
}
+rtc::ArrayView<int16_t> GetMutableFrameData(AudioFrame* frame) {
+ int16_t* ptr = frame->mutable_data();
+ const size_t len = frame->samples_per_channel() * frame->num_channels();
+ return rtc::ArrayView<int16_t>(ptr, len);
+}
+
+rtc::ArrayView<const int16_t> GetFrameData(const AudioFrame& frame) {
+ const int16_t* ptr = frame.data();
+ const size_t len = frame.samples_per_channel() * frame.num_channels();
+ return rtc::ArrayView<const int16_t>(ptr, len);
+}
+
void EnableAllAPComponents(AudioProcessing* ap) {
AudioProcessing::Config apm_config = ap->GetConfig();
apm_config.echo_canceller.enabled = true;
@@ -842,6 +855,75 @@
}
}
+// This test repeatedly reconfigures the pre-amplifier in APM, processes a
+// number of frames, and checks that output signal has the right level.
+TEST_F(ApmTest, PreAmplifier) {
+ // Fill the audio frame with a sawtooth pattern.
+ rtc::ArrayView<int16_t> frame_data = GetMutableFrameData(frame_);
+ const size_t samples_per_channel = frame_->samples_per_channel();
+ for (size_t i = 0; i < samples_per_channel; i++) {
+ for (size_t ch = 0; ch < frame_->num_channels(); ++ch) {
+ frame_data[i + ch * samples_per_channel] = 10000 * ((i % 3) - 1);
+ }
+ }
+ // Cache the frame in tmp_frame.
+ AudioFrame tmp_frame;
+ tmp_frame.CopyFrom(*frame_);
+
+ auto compute_power = [](const AudioFrame& frame) {
+ rtc::ArrayView<const int16_t> data = GetFrameData(frame);
+ return std::accumulate(data.begin(), data.end(), 0.0f,
+ [](float a, float b) { return a + b * b; }) /
+ data.size() / 32768 / 32768;
+ };
+
+ const float input_power = compute_power(tmp_frame);
+ // Double-check that the input data is large compared to the error kEpsilon.
+ constexpr float kEpsilon = 1e-4f;
+ RTC_DCHECK_GE(input_power, 10 * kEpsilon);
+
+ // 1. Enable pre-amp with 0 dB gain.
+ AudioProcessing::Config config = apm_->GetConfig();
+ config.pre_amplifier.enabled = true;
+ config.pre_amplifier.fixed_gain_factor = 1.0f;
+ apm_->ApplyConfig(config);
+
+ for (int i = 0; i < 20; ++i) {
+ frame_->CopyFrom(tmp_frame);
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
+ }
+ float output_power = compute_power(*frame_);
+ EXPECT_NEAR(output_power, input_power, kEpsilon);
+ config = apm_->GetConfig();
+ EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.0f);
+
+ // 2. Change pre-amp gain via ApplyConfig.
+ config.pre_amplifier.fixed_gain_factor = 2.0f;
+ apm_->ApplyConfig(config);
+
+ for (int i = 0; i < 20; ++i) {
+ frame_->CopyFrom(tmp_frame);
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
+ }
+ output_power = compute_power(*frame_);
+ EXPECT_NEAR(output_power, 4 * input_power, kEpsilon);
+ config = apm_->GetConfig();
+ EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 2.0f);
+
+ // 3. Change pre-amp gain via a RuntimeSetting.
+ apm_->SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting::CreateCapturePreGain(1.5f));
+
+ for (int i = 0; i < 20; ++i) {
+ frame_->CopyFrom(tmp_frame);
+ EXPECT_EQ(apm_->kNoError, ProcessStreamChooser(kIntFormat));
+ }
+ output_power = compute_power(*frame_);
+ EXPECT_NEAR(output_power, 2.25 * input_power, kEpsilon);
+ config = apm_->GetConfig();
+ EXPECT_EQ(config.pre_amplifier.fixed_gain_factor, 1.5f);
+}
+
TEST_F(ApmTest, GainControl) {
AudioProcessing::Config config = apm_->GetConfig();
config.gain_controller1.enabled = false;