Add refined handling of the internal scaling of the audio in APM
This CL adds functionality that allows adjusting the audio levels
internally in APM. The main purpose of the functionality is to allow
APM to optionally be moved to an integration that does not provide an
analog gain to control, and the implementation of this has been
tailored specifically to meet the requirements for that.
More specifically, this CL does
-Add a new variant of the pre-amplifier gain that is intended to replace
the pre-amplifier gain (but at the moment can coexist with that). The
main differences with the pre-amplifier gain is that an attenuating
gain is allowed, the gain is applied jointly with any emulated analog
gain, and that its packaging fits better with the post gain.
-Add an emulation of an analog microphone gain. The emulation is
designed to match the analog mic gain functionality in Chrome OS (which
is digital) but should be usable also on other platforms.
-Add a post-gain which is applied after all processing has been applied.
The purpose of this gain is for it to work well with the integration
in ChromeOS, and be used to compensate for the offset that there is
applied on some USB audio devices.
Bug: b/177830918
Change-Id: I0f312996e4088c9bd242a713a703eaaeb17f188a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/209707
Commit-Queue: Per Åhgren <peah@webrtc.org>
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33466}
diff --git a/modules/audio_processing/audio_processing_impl_unittest.cc b/modules/audio_processing/audio_processing_impl_unittest.cc
index 65de4d6..ef18303 100644
--- a/modules/audio_processing/audio_processing_impl_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_unittest.cc
@@ -203,6 +203,72 @@
<< "Frame should be amplified.";
}
+TEST(AudioProcessingImplTest,
+ LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
+ std::unique_ptr<AudioProcessing> apm(
+ AudioProcessingBuilderForTesting().Create());
+ webrtc::AudioProcessing::Config apm_config;
+ apm_config.capture_level_adjustment.enabled = true;
+ apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
+ apm->ApplyConfig(apm_config);
+
+ constexpr int kSampleRateHz = 48000;
+ constexpr int16_t kAudioLevel = 10000;
+ constexpr size_t kNumChannels = 2;
+
+ std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
+ StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
+ frame.fill(kAudioLevel);
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+ EXPECT_EQ(frame[100], kAudioLevel)
+ << "With factor 1, frame shouldn't be modified.";
+
+ constexpr float kGainFactor = 2.f;
+ apm->SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
+
+ // Process for two frames to have time to ramp up gain.
+ for (int i = 0; i < 2; ++i) {
+ frame.fill(kAudioLevel);
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+ }
+ EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
+ << "Frame should be amplified.";
+}
+
+TEST(AudioProcessingImplTest,
+ LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
+ std::unique_ptr<AudioProcessing> apm(
+ AudioProcessingBuilderForTesting().Create());
+ webrtc::AudioProcessing::Config apm_config;
+ apm_config.capture_level_adjustment.enabled = true;
+ apm_config.capture_level_adjustment.post_gain_factor = 1.f;
+ apm->ApplyConfig(apm_config);
+
+ constexpr int kSampleRateHz = 48000;
+ constexpr int16_t kAudioLevel = 10000;
+ constexpr size_t kNumChannels = 2;
+
+ std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
+ StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
+ frame.fill(kAudioLevel);
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+ EXPECT_EQ(frame[100], kAudioLevel)
+ << "With factor 1, frame shouldn't be modified.";
+
+ constexpr float kGainFactor = 2.f;
+ apm->SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
+
+ // Process for two frames to have time to ramp up gain.
+ for (int i = 0; i < 2; ++i) {
+ frame.fill(kAudioLevel);
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+ }
+ EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
+ << "Frame should be amplified.";
+}
+
TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
// Tests that the echo controller observes that the capture usage has been
// updated.
@@ -329,6 +395,49 @@
}
TEST(AudioProcessingImplTest,
+ EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
+ // Tests that the echo controller observes an echo path gain change when the
+ // pre-amplifier submodule changes the gain.
+ auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
+ const auto* echo_control_factory_ptr = echo_control_factory.get();
+
+ std::unique_ptr<AudioProcessing> apm(
+ AudioProcessingBuilderForTesting()
+ .SetEchoControlFactory(std::move(echo_control_factory))
+ .Create());
+ // Disable AGC.
+ webrtc::AudioProcessing::Config apm_config;
+ apm_config.gain_controller1.enabled = false;
+ apm_config.gain_controller2.enabled = false;
+ apm_config.capture_level_adjustment.enabled = true;
+ apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
+ apm->ApplyConfig(apm_config);
+
+ constexpr int16_t kAudioLevel = 10000;
+ constexpr size_t kSampleRateHz = 48000;
+ constexpr size_t kNumChannels = 2;
+ std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
+ StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
+ frame.fill(kAudioLevel);
+
+ MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
+
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
+ EXPECT_CALL(*echo_control_mock,
+ ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
+ .Times(1);
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+
+ EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
+ EXPECT_CALL(*echo_control_mock,
+ ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
+ .Times(1);
+ apm->SetRuntimeSetting(
+ AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
+ apm->ProcessStream(frame.data(), config, config, frame.data());
+}
+
+TEST(AudioProcessingImplTest,
EchoControllerObservesAnalogAgc1EchoPathGainChange) {
// Tests that the echo controller observes an echo path gain change when the
// AGC1 analog adaptive submodule changes the analog gain.