From e277bde7e424654bae7726bb5fe56daa16ffdea1 Mon Sep 17 00:00:00 2001 From: Sam Zackrisson Date: Fri, 25 Oct 2019 10:07:54 +0200 Subject: [PATCH] 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 Reviewed-by: Alessio Bazzica Cr-Commit-Position: refs/heads/master@{#29607} --- .../audio_processing_unittest.cc | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc index 5f2ce87e10..c7d325c69b 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "absl/flags/flag.h" @@ -172,6 +173,18 @@ bool FrameDataAreEqual(const AudioFrame& frame1, const AudioFrame& frame2) { return true; } +rtc::ArrayView GetMutableFrameData(AudioFrame* frame) { + int16_t* ptr = frame->mutable_data(); + const size_t len = frame->samples_per_channel() * frame->num_channels(); + return rtc::ArrayView(ptr, len); +} + +rtc::ArrayView GetFrameData(const AudioFrame& frame) { + const int16_t* ptr = frame.data(); + const size_t len = frame.samples_per_channel() * frame.num_channels(); + return rtc::ArrayView(ptr, len); +} + void EnableAllAPComponents(AudioProcessing* ap) { AudioProcessing::Config apm_config = ap->GetConfig(); apm_config.echo_canceller.enabled = true; @@ -842,6 +855,75 @@ TEST_F(ApmTest, SampleRatesInt) { } } +// 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 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 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;