aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorHanna Silen <silen@webrtc.org>2022-11-30 15:16:21 +0100
committerWebRTC LUCI CQ <webrtc-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-11-30 15:32:23 +0000
commitd4dbe4527d147ed0c96b81e7fb3c6e40f7a5c7d0 (patch)
treeb4f7fe163db2b46ac2004bb2631e1899d50f07c0 /modules
parent256d3ee2bfdefc5c623b319191d5d5b7a28ab208 (diff)
downloadwebrtc-d4dbe4527d147ed0c96b81e7fb3c6e40f7a5c7d0.tar.gz
AudioProcessingImpl: Add the use of AGC2 InputVolumeController
The integration relies on GainController2 methods Process() and GetRecommendedInputVolume() to internally take into account whether the input volume controller is enabled in the ctor or not. These methods are called for every frame processed if GainController2 is enabled. Analyze() is called if the input volume controller is enabled. The functionality can be enabled from the APM config and is not enabled by default. If multiple input volume controllers are enabled, an error is logged. Tested: Bitexact on a large number of aecdumps if not enabled Bug: webrtc:7494 Change-Id: I9105483be34eb95fab3c46afbbd368802e956fad Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/282720 Reviewed-by: Alessio Bazzica <alessiob@webrtc.org> Reviewed-by: Sam Zackrisson <saza@webrtc.org> Commit-Queue: Hanna Silen <silen@webrtc.org> Reviewed-by: Per Ã…hgren <peah@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38776}
Diffstat (limited to 'modules')
-rw-r--r--modules/audio_processing/audio_processing_impl.cc39
-rw-r--r--modules/audio_processing/audio_processing_impl_unittest.cc155
2 files changed, 162 insertions, 32 deletions
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 6dba8d7e63..96193fb1a7 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -830,6 +830,10 @@ void AudioProcessingImpl::HandleCaptureOutputUsedSetting(
submodules_.noise_suppressor->SetCaptureOutputUsage(
capture_.capture_output_used);
}
+ if (submodules_.gain_controller2) {
+ submodules_.gain_controller2->SetCaptureOutputUsed(
+ capture_.capture_output_used);
+ }
}
void AudioProcessingImpl::SetRuntimeSetting(RuntimeSetting setting) {
@@ -1001,7 +1005,9 @@ void AudioProcessingImpl::HandleCaptureRuntimeSettings() {
// TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump.
break;
case RuntimeSetting::Type::kCaptureCompressionGain: {
- if (!submodules_.agc_manager) {
+ if (!submodules_.agc_manager &&
+ !(submodules_.gain_controller2 &&
+ config_.gain_controller2.input_volume_controller.enabled)) {
float value;
setting.GetFloat(&value);
int int_value = static_cast<int>(value + .5f);
@@ -1337,6 +1343,16 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
submodules_.agc_manager->AnalyzePreProcess(*capture_buffer);
}
+ if (submodules_.gain_controller2 &&
+ config_.gain_controller2.input_volume_controller.enabled) {
+ // Expect the volume to be available if the input controller is enabled.
+ RTC_DCHECK(capture_.applied_input_volume.has_value());
+ if (capture_.applied_input_volume.has_value()) {
+ submodules_.gain_controller2->Analyze(*capture_.applied_input_volume,
+ *capture_buffer);
+ }
+ }
+
if (submodule_states_.CaptureMultiBandSubModulesActive() &&
SampleRateSupportsMultiBand(
capture_nonlocked_.capture_processing_format.sample_rate_hz())) {
@@ -1490,6 +1506,8 @@ int AudioProcessingImpl::ProcessCaptureStreamLocked() {
}
if (submodules_.gain_controller2) {
+ // TODO(bugs.webrtc.org/7494): Let AGC2 detect applied input volume
+ // changes.
submodules_.gain_controller2->Process(
voice_probability, capture_.applied_input_volume_changed,
capture_buffer);
@@ -1819,6 +1837,13 @@ void AudioProcessingImpl::UpdateRecommendedInputVolumeLocked() {
return;
}
+ if (submodules_.gain_controller2 &&
+ config_.gain_controller2.input_volume_controller.enabled) {
+ capture_.recommended_input_volume =
+ submodules_.gain_controller2->GetRecommendedInputVolume();
+ return;
+ }
+
capture_.recommended_input_volume = capture_.applied_input_volume;
}
@@ -2017,6 +2042,16 @@ void AudioProcessingImpl::InitializeEchoController() {
}
void AudioProcessingImpl::InitializeGainController1() {
+ if (config_.gain_controller2.enabled &&
+ config_.gain_controller2.input_volume_controller.enabled &&
+ config_.gain_controller1.enabled &&
+ (config_.gain_controller1.mode ==
+ AudioProcessing::Config::GainController1::kAdaptiveAnalog ||
+ config_.gain_controller1.analog_gain_controller.enabled)) {
+ RTC_LOG(LS_ERROR) << "APM configuration not valid: "
+ << "Multiple input volume controllers enabled.";
+ }
+
if (!config_.gain_controller1.enabled) {
submodules_.agc_manager.reset();
submodules_.gain_control.reset();
@@ -2090,6 +2125,8 @@ void AudioProcessingImpl::InitializeGainController2(bool config_has_changed) {
submodules_.gain_controller2 = std::make_unique<GainController2>(
config_.gain_controller2, proc_fullband_sample_rate_hz(),
num_input_channels(), use_internal_vad);
+ submodules_.gain_controller2->SetCaptureOutputUsed(
+ capture_.capture_output_used);
}
}
diff --git a/modules/audio_processing/audio_processing_impl_unittest.cc b/modules/audio_processing/audio_processing_impl_unittest.cc
index 21365e075e..fea7a8c74e 100644
--- a/modules/audio_processing/audio_processing_impl_unittest.cc
+++ b/modules/audio_processing/audio_processing_impl_unittest.cc
@@ -132,13 +132,20 @@ class TestRenderPreProcessor : public CustomProcessing {
};
// Creates a simple `AudioProcessing` instance for APM input volume testing
-// with analog and digital AGC enabled.
-rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest() {
+// with AGC1 analog and/or AGC2 input volume controller enabled and AGC2
+// digital controller enabled.
+rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest(
+ bool agc1_analog_gain_controller_enabled,
+ bool agc2_input_volume_controller_enabled) {
webrtc::AudioProcessing::Config config;
- // Enable AGC1 analog.
- config.gain_controller1.enabled = true;
- config.gain_controller1.analog_gain_controller.enabled = true;
- // Enable AGC2 adaptive digital.
+ // Enable AGC1 analog controller.
+ config.gain_controller1.enabled = agc1_analog_gain_controller_enabled;
+ config.gain_controller1.analog_gain_controller.enabled =
+ agc1_analog_gain_controller_enabled;
+ // Enable AG2 input volume controller
+ config.gain_controller2.input_volume_controller.enabled =
+ agc2_input_volume_controller_enabled;
+ // Enable AGC2 adaptive digital controller.
config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
false;
config.gain_controller2.enabled = true;
@@ -146,6 +153,7 @@ rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest() {
auto apm(AudioProcessingBuilder().Create());
apm->ApplyConfig(config);
+
return apm;
}
@@ -177,25 +185,30 @@ int ProcessInputVolume(AudioProcessing& apm,
constexpr char kMinMicLevelFieldTrial[] =
"WebRTC-Audio-2ndAgcMinMicLevelExperiment";
+constexpr char kMinInputVolumeFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume";
constexpr int kMinInputVolume = 12;
std::string GetMinMicLevelExperimentFieldTrial(absl::optional<int> value) {
- char field_trial_buffer[64];
+ char field_trial_buffer[128];
rtc::SimpleStringBuilder builder(field_trial_buffer);
if (value.has_value()) {
RTC_DCHECK_GE(*value, 0);
RTC_DCHECK_LE(*value, 255);
builder << kMinMicLevelFieldTrial << "/Enabled-" << *value << "/";
+ builder << kMinInputVolumeFieldTrial << "/Enabled-" << *value << "/";
} else {
builder << kMinMicLevelFieldTrial << "/Disabled/";
+ builder << kMinInputVolumeFieldTrial << "/Disabled/";
}
return builder.str();
}
// TODO(webrtc:7494): Remove the fieldtrial from the input volume tests when
-// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is removed.
+// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" and
+// "WebRTC-Audio-Agc2-MinInputVolume" are removed.
class InputVolumeStartupParameterizedTest
- : public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
+ : public ::testing::TestWithParam<
+ std::tuple<int, absl::optional<int>, bool, bool>> {
protected:
InputVolumeStartupParameterizedTest()
: field_trials_(
@@ -204,6 +217,12 @@ class InputVolumeStartupParameterizedTest
int GetMinVolume() const {
return std::get<1>(GetParam()).value_or(kMinInputVolume);
}
+ bool GetAgc1AnalogControllerEnabled() const {
+ return std::get<2>(GetParam());
+ }
+ bool GetAgc2InputVolumeControllerEnabled() const {
+ return std::get<3>(GetParam());
+ }
private:
test::ScopedFieldTrials field_trials_;
@@ -211,7 +230,7 @@ class InputVolumeStartupParameterizedTest
class InputVolumeNotZeroParameterizedTest
: public ::testing::TestWithParam<
- std::tuple<int, int, absl::optional<int>>> {
+ std::tuple<int, int, absl::optional<int>, bool, bool>> {
protected:
InputVolumeNotZeroParameterizedTest()
: field_trials_(
@@ -224,13 +243,20 @@ class InputVolumeNotZeroParameterizedTest
bool GetMinMicLevelExperimentEnabled() {
return std::get<2>(GetParam()).has_value();
}
+ bool GetAgc1AnalogControllerEnabled() const {
+ return std::get<3>(GetParam());
+ }
+ bool GetAgc2InputVolumeControllerEnabled() const {
+ return std::get<4>(GetParam());
+ }
private:
test::ScopedFieldTrials field_trials_;
};
class InputVolumeZeroParameterizedTest
- : public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
+ : public ::testing::TestWithParam<
+ std::tuple<int, absl::optional<int>, bool, bool>> {
protected:
InputVolumeZeroParameterizedTest()
: field_trials_(
@@ -239,6 +265,12 @@ class InputVolumeZeroParameterizedTest
int GetMinVolume() const {
return std::get<1>(GetParam()).value_or(kMinInputVolume);
}
+ bool GetAgc1AnalogControllerEnabled() const {
+ return std::get<2>(GetParam());
+ }
+ bool GetAgc2InputVolumeControllerEnabled() const {
+ return std::get<3>(GetParam());
+ }
private:
test::ScopedFieldTrials field_trials_;
@@ -934,33 +966,57 @@ TEST_P(InputVolumeStartupParameterizedTest,
const int applied_startup_input_volume = GetStartupVolume();
const int expected_volume =
std::max(applied_startup_input_volume, GetMinVolume());
- auto apm = CreateApmForInputVolumeTest();
+ const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
+ const bool agc2_input_volume_controller_enabled =
+ GetAgc2InputVolumeControllerEnabled();
+ auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
+ agc2_input_volume_controller_enabled);
const int recommended_input_volume =
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
- ASSERT_EQ(recommended_input_volume, expected_volume);
+ if (!agc1_analog_controller_enabled &&
+ !agc2_input_volume_controller_enabled) {
+ // No input volume changes if none of the analog controllers is enabled.
+ ASSERT_EQ(recommended_input_volume, applied_startup_input_volume);
+ } else {
+ ASSERT_EQ(recommended_input_volume, expected_volume);
+ }
}
// Tests that the minimum input volume is applied if the volume is manually
-// adjusted to a non-zero value only if
-// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled.
+// adjusted to a non-zero value 1) always for AGC2 input volume controller and
+// 2) only if "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled for AGC1
+// analog controller.
TEST_P(InputVolumeNotZeroParameterizedTest,
VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
const int applied_startup_input_volume = GetStartupVolume();
const int applied_input_volume = GetVolume();
const int expected_volume = std::max(applied_input_volume, GetMinVolume());
- auto apm = CreateApmForInputVolumeTest();
+ const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
+ const bool agc2_input_volume_controller_enabled =
+ GetAgc2InputVolumeControllerEnabled();
+ auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
+ agc2_input_volume_controller_enabled);
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
const int recommended_input_volume =
ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
ASSERT_NE(applied_input_volume, 0);
- if (GetMinMicLevelExperimentEnabled()) {
- ASSERT_EQ(recommended_input_volume, expected_volume);
- } else {
+
+ if (!agc1_analog_controller_enabled &&
+ !agc2_input_volume_controller_enabled) {
+ // No input volume changes if none of the analog controllers is enabled.
ASSERT_EQ(recommended_input_volume, applied_input_volume);
+ } else {
+ if (GetMinMicLevelExperimentEnabled() ||
+ (!agc1_analog_controller_enabled &&
+ agc2_input_volume_controller_enabled)) {
+ ASSERT_EQ(recommended_input_volume, expected_volume);
+ } else {
+ ASSERT_EQ(recommended_input_volume, applied_input_volume);
+ }
}
}
@@ -970,15 +1026,25 @@ TEST_P(InputVolumeZeroParameterizedTest,
VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
constexpr int kZeroVolume = 0;
const int applied_startup_input_volume = GetStartupVolume();
- auto apm = CreateApmForInputVolumeTest();
+ const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
+ const bool agc2_input_volume_controller_enabled =
+ GetAgc2InputVolumeControllerEnabled();
+ auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
+ agc2_input_volume_controller_enabled);
const int recommended_input_volume_after_startup =
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
const int recommended_input_volume =
ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
- ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
- ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ if (!agc1_analog_controller_enabled &&
+ !agc2_input_volume_controller_enabled) {
+ // No input volume changes if none of the analog controllers is enabled.
+ ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ } else {
+ ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
+ ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ }
}
// Tests that the minimum input volume is applied if the volume is not zero
@@ -987,15 +1053,26 @@ TEST_P(InputVolumeNotZeroParameterizedTest,
VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
const int applied_startup_input_volume = GetStartupVolume();
const int applied_input_volume = GetVolume();
- auto apm = CreateApmForInputVolumeTest();
+ const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
+ const bool agc2_input_volume_controller_enabled =
+ GetAgc2InputVolumeControllerEnabled();
+ auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
+ agc2_input_volume_controller_enabled);
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
const int recommended_input_volume =
ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
ASSERT_NE(applied_input_volume, 0);
- if (recommended_input_volume != applied_input_volume) {
- ASSERT_GE(recommended_input_volume, GetMinVolume());
+
+ if (!agc1_analog_controller_enabled &&
+ !agc2_input_volume_controller_enabled) {
+ // No input volume changes if none of the analog controllers is enabled.
+ ASSERT_EQ(recommended_input_volume, applied_input_volume);
+ } else {
+ if (recommended_input_volume != applied_input_volume) {
+ ASSERT_GE(recommended_input_volume, GetMinVolume());
+ }
}
}
@@ -1005,35 +1082,51 @@ TEST_P(InputVolumeZeroParameterizedTest,
VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
constexpr int kZeroVolume = 0;
const int applied_startup_input_volume = GetStartupVolume();
- auto apm = CreateApmForInputVolumeTest();
+ const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
+ const bool agc2_input_volume_controller_enabled =
+ GetAgc2InputVolumeControllerEnabled();
+ auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
+ agc2_input_volume_controller_enabled);
const int recommended_input_volume_after_startup =
ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
const int recommended_input_volume =
ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
- ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
- ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ if (!agc1_analog_controller_enabled &&
+ !agc2_input_volume_controller_enabled) {
+ // No input volume changes if none of the analog controllers is enabled.
+ ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ } else {
+ ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
+ ASSERT_EQ(recommended_input_volume, kZeroVolume);
+ }
}
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
InputVolumeStartupParameterizedTest,
::testing::Combine(::testing::Values(0, 5, 30),
::testing::Values(absl::nullopt,
- 20)));
+ 20),
+ ::testing::Bool(),
+ ::testing::Bool()));
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
InputVolumeNotZeroParameterizedTest,
::testing::Combine(::testing::Values(0, 5, 15),
::testing::Values(1, 5, 30),
::testing::Values(absl::nullopt,
- 20)));
+ 20),
+ ::testing::Bool(),
+ ::testing::Bool()));
INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
InputVolumeZeroParameterizedTest,
::testing::Combine(::testing::Values(0, 5, 15),
::testing::Values(absl::nullopt,
- 20)));
+ 20),
+ ::testing::Bool(),
+ ::testing::Bool()));
// When the input volume is not emulated and no input volume controller is
// active, the recommended volume must always be the applied volume.