mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
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}
This commit is contained in:
parent
256d3ee2bf
commit
d4dbe4527d
2 changed files with 162 additions and 32 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue