From ca6535593fa0b174257b631fe2fe53d4de1f0d57 Mon Sep 17 00:00:00 2001 From: Hanna Silen Date: Thu, 8 Dec 2022 17:40:01 +0100 Subject: [PATCH] APM: Add field trial parameters and rename Add AGC2 digital adaptive config parameters in the field trial "WebRTC-Audio-InputVolumeControllerExperiment". Rename it as "WebRTC-Audio-GainController2" to reflect that the override now adjusts the parameters for both input volume controller and adaptive digital controller. Bug: webrtc:7494 Change-Id: Ifbc1b8be76cf23b0b6b74b22b5167a45972cab38 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/286880 Reviewed-by: Alessio Bazzica Commit-Queue: Hanna Silen Cr-Commit-Position: refs/heads/main@{#38855} --- .../audio_processing/audio_processing_impl.cc | 148 ++++++++++++------ .../audio_processing/audio_processing_impl.h | 22 ++- .../audio_processing_impl_unittest.cc | 56 +++++-- 3 files changed, 160 insertions(+), 66 deletions(-) diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index c1a275653f..3200ea4d9c 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -325,83 +325,124 @@ int HandleUnsupportedAudioFormats(const float* const* src, return error_code; } -const absl::optional -GetInputVolumeControllerConfigOverride() { - constexpr char kInputVolumeControllerFieldTrial[] = - "WebRTC-Audio-InputVolumeControllerExperiment"; +const absl::optional +GetGainController2ConfigOverride() { + constexpr char kFieldTrialName[] = "WebRTC-Audio-GainController2"; - if (!field_trial::IsEnabled(kInputVolumeControllerFieldTrial)) { + if (!field_trial::IsEnabled(kFieldTrialName)) { return absl::nullopt; } - constexpr InputVolumeController::Config kDefaultConfig; + constexpr InputVolumeController::Config kDefaultInputVolumeControllerConfig; FieldTrialFlag enabled("Enabled", false); FieldTrialConstrained clipped_level_min( - "clipped_level_min", kDefaultConfig.clipped_level_min, 0, 255); + "clipped_level_min", + kDefaultInputVolumeControllerConfig.clipped_level_min, 0, 255); FieldTrialConstrained clipped_level_step( - "clipped_level_step", kDefaultConfig.clipped_level_step, 0, 255); + "clipped_level_step", + kDefaultInputVolumeControllerConfig.clipped_level_step, 0, 255); FieldTrialConstrained clipped_ratio_threshold( - "clipped_ratio_threshold", kDefaultConfig.clipped_ratio_threshold, 0, 1); + "clipped_ratio_threshold", + kDefaultInputVolumeControllerConfig.clipped_ratio_threshold, 0, 1); FieldTrialConstrained clipped_wait_frames( - "clipped_wait_frames", kDefaultConfig.clipped_wait_frames, 0, + "clipped_wait_frames", + kDefaultInputVolumeControllerConfig.clipped_wait_frames, 0, absl::nullopt); FieldTrialParameter enable_clipping_predictor( - "enable_clipping_predictor", kDefaultConfig.enable_clipping_predictor); + "enable_clipping_predictor", + kDefaultInputVolumeControllerConfig.enable_clipping_predictor); FieldTrialConstrained target_range_max_dbfs( - "target_range_max_dbfs", kDefaultConfig.target_range_max_dbfs, -90, 30); + "target_range_max_dbfs", + kDefaultInputVolumeControllerConfig.target_range_max_dbfs, -90, 30); FieldTrialConstrained target_range_min_dbfs( - "target_range_min_dbfs", kDefaultConfig.target_range_min_dbfs, -90, 30); + "target_range_min_dbfs", + kDefaultInputVolumeControllerConfig.target_range_min_dbfs, -90, 30); FieldTrialConstrained update_input_volume_wait_frames( "update_input_volume_wait_frames", - kDefaultConfig.update_input_volume_wait_frames, 0, absl::nullopt); + kDefaultInputVolumeControllerConfig.update_input_volume_wait_frames, 0, + absl::nullopt); FieldTrialConstrained speech_probability_threshold( "speech_probability_threshold", - kDefaultConfig.speech_probability_threshold, 0, 1); + kDefaultInputVolumeControllerConfig.speech_probability_threshold, 0, 1); FieldTrialConstrained speech_ratio_threshold( - "speech_ratio_threshold", kDefaultConfig.speech_ratio_threshold, 0, 1); + "speech_ratio_threshold", + kDefaultInputVolumeControllerConfig.speech_ratio_threshold, 0, 1); - // Field-trial based override for the input volume controller config. + constexpr AudioProcessing::Config::GainController2::AdaptiveDigital + kDefaultAdaptiveDigitalConfig; + + FieldTrialConstrained headroom_db( + "headroom_db", kDefaultAdaptiveDigitalConfig.headroom_db, 0, + absl::nullopt); + FieldTrialConstrained max_gain_db( + "max_gain_db", kDefaultAdaptiveDigitalConfig.max_gain_db, 0, + absl::nullopt); + FieldTrialConstrained max_gain_change_db_per_second( + "max_gain_change_db_per_second", + kDefaultAdaptiveDigitalConfig.max_gain_change_db_per_second, 0, + absl::nullopt); + FieldTrialConstrained max_output_noise_level_dbfs( + "max_output_noise_level_dbfs", + kDefaultAdaptiveDigitalConfig.max_output_noise_level_dbfs, absl::nullopt, + 0); + + // Field-trial based override for the input volume controller and adaptive + // digital configs. const std::string field_trial_name = - field_trial::FindFullName(kInputVolumeControllerFieldTrial); + field_trial::FindFullName(kFieldTrialName); ParseFieldTrial({&enabled, &clipped_level_min, &clipped_level_step, &clipped_ratio_threshold, &clipped_wait_frames, &enable_clipping_predictor, &target_range_max_dbfs, &target_range_min_dbfs, &update_input_volume_wait_frames, - &speech_probability_threshold, &speech_ratio_threshold}, + &speech_probability_threshold, &speech_ratio_threshold, + &headroom_db, &max_gain_db, &max_gain_change_db_per_second, + &max_output_noise_level_dbfs}, field_trial_name); // Checked already by `IsEnabled()` before parsing, therefore always true. RTC_DCHECK(enabled); - return InputVolumeController::Config{ - .clipped_level_min = static_cast(clipped_level_min.Get()), - .clipped_level_step = static_cast(clipped_level_step.Get()), - .clipped_ratio_threshold = - static_cast(clipped_ratio_threshold.Get()), - .clipped_wait_frames = static_cast(clipped_wait_frames.Get()), - .enable_clipping_predictor = - static_cast(enable_clipping_predictor.Get()), - .target_range_max_dbfs = static_cast(target_range_max_dbfs.Get()), - .target_range_min_dbfs = static_cast(target_range_min_dbfs.Get()), - .update_input_volume_wait_frames = - static_cast(update_input_volume_wait_frames.Get()), - .speech_probability_threshold = - static_cast(speech_probability_threshold.Get()), - .speech_ratio_threshold = - static_cast(speech_ratio_threshold.Get()), + return AudioProcessingImpl::GainController2ConfigOverride{ + InputVolumeController::Config{ + .clipped_level_min = static_cast(clipped_level_min.Get()), + .clipped_level_step = static_cast(clipped_level_step.Get()), + .clipped_ratio_threshold = + static_cast(clipped_ratio_threshold.Get()), + .clipped_wait_frames = static_cast(clipped_wait_frames.Get()), + .enable_clipping_predictor = + static_cast(enable_clipping_predictor.Get()), + .target_range_max_dbfs = + static_cast(target_range_max_dbfs.Get()), + .target_range_min_dbfs = + static_cast(target_range_min_dbfs.Get()), + .update_input_volume_wait_frames = + static_cast(update_input_volume_wait_frames.Get()), + .speech_probability_threshold = + static_cast(speech_probability_threshold.Get()), + .speech_ratio_threshold = + static_cast(speech_ratio_threshold.Get()), + }, + AudioProcessingImpl::GainController2ConfigOverride::AdaptiveDigitalConfig{ + .headroom_db = static_cast(headroom_db.Get()), + .max_gain_db = static_cast(max_gain_db.Get()), + .max_gain_change_db_per_second = + static_cast(max_gain_change_db_per_second.Get()), + .max_output_noise_level_dbfs = + static_cast(max_output_noise_level_dbfs.Get()), + }, }; } // If `disallow_transient_supporessor_usage` is true, disables transient -// suppression. When `input_volume_controller_config_override` is specified, +// suppression. When `gain_controller2_config_override` is specified, // switches all gain control to AGC2. AudioProcessing::Config AdjustConfig( const AudioProcessing::Config& config, bool disallow_transient_supporessor_usage, - const absl::optional& - input_volume_controller_config_override) { + const absl::optional& + gain_controller2_config_override) { AudioProcessing::Config adjusted_config = config; // Override the transient suppressor configuration. @@ -410,15 +451,14 @@ AudioProcessing::Config AdjustConfig( } // Override the auto gain control configuration if the AGC1 analog gain - // controller is active and `input_volume_controller_config_override` is + // controller is active and `gain_controller2_config_override` is // specified. const bool agc1_analog_enabled = config.gain_controller1.enabled && (config.gain_controller1.mode == AudioProcessing::Config::GainController1::kAdaptiveAnalog || config.gain_controller1.analog_gain_controller.enabled); - if (agc1_analog_enabled && - input_volume_controller_config_override.has_value()) { + if (agc1_analog_enabled && gain_controller2_config_override.has_value()) { // Check that the unadjusted AGC config meets the preconditions. const bool hybrid_agc_config_detected = config.gain_controller1.enabled && @@ -447,9 +487,23 @@ AudioProcessing::Config AdjustConfig( } else { adjusted_config.gain_controller1.enabled = false; adjusted_config.gain_controller1.analog_gain_controller.enabled = false; + adjusted_config.gain_controller2.enabled = true; adjusted_config.gain_controller2.adaptive_digital.enabled = true; adjusted_config.gain_controller2.input_volume_controller.enabled = true; + + auto& adjusted_adaptive_digital = // Alias. + adjusted_config.gain_controller2.adaptive_digital; + const auto& adaptive_digital_override = // Alias. + gain_controller2_config_override->adaptive_digital_config; + adjusted_adaptive_digital.headroom_db = + adaptive_digital_override.headroom_db; + adjusted_adaptive_digital.max_gain_db = + adaptive_digital_override.max_gain_db; + adjusted_adaptive_digital.max_gain_change_db_per_second = + adaptive_digital_override.max_gain_change_db_per_second; + adjusted_adaptive_digital.max_output_noise_level_dbfs = + adaptive_digital_override.max_output_noise_level_dbfs; } } @@ -593,8 +647,7 @@ AudioProcessingImpl::AudioProcessingImpl( : data_dumper_(new ApmDataDumper(instance_count_.fetch_add(1) + 1)), use_setup_specific_default_aec3_config_( UseSetupSpecificDefaultAec3Congfig()), - input_volume_controller_config_override_( - GetInputVolumeControllerConfigOverride()), + gain_controller2_config_override_(GetGainController2ConfigOverride()), use_denormal_disabler_( !field_trial::IsEnabled("WebRTC-ApmDenormalDisablerKillSwitch")), disallow_transient_supporessor_usage_( @@ -607,7 +660,7 @@ AudioProcessingImpl::AudioProcessingImpl( echo_control_factory_(std::move(echo_control_factory)), config_(AdjustConfig(config, disallow_transient_supporessor_usage_, - input_volume_controller_config_override_)), + gain_controller2_config_override_)), submodule_states_(!!capture_post_processor, !!render_pre_processor, !!capture_analyzer), @@ -844,7 +897,7 @@ void AudioProcessingImpl::ApplyConfig(const AudioProcessing::Config& config) { const auto adjusted_config = AdjustConfig(config, disallow_transient_supporessor_usage_, - input_volume_controller_config_override_); + gain_controller2_config_override_); RTC_LOG(LS_INFO) << "AudioProcessing::ApplyConfig: " << adjusted_config.ToString(); @@ -2292,8 +2345,9 @@ void AudioProcessingImpl::InitializeGainController2(bool config_has_changed) { transient_suppressor_vad_mode_ != TransientSuppressor::VadMode::kRnnVad; submodules_.gain_controller2 = std::make_unique( config_.gain_controller2, - input_volume_controller_config_override_.value_or( - InputVolumeController::Config{}), + gain_controller2_config_override_.has_value() + ? gain_controller2_config_override_->input_volume_controller_config + : InputVolumeController::Config{}, 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.h b/modules/audio_processing/audio_processing_impl.h index 66e98dc304..189ed03773 100644 --- a/modules/audio_processing/audio_processing_impl.h +++ b/modules/audio_processing/audio_processing_impl.h @@ -138,6 +138,18 @@ class AudioProcessingImpl : public AudioProcessing { AudioProcessing::Config GetConfig() const override; + // TODO(bugs.webrtc.org/7494): Remove when the related field trial is + // removed. + struct GainController2ConfigOverride { + InputVolumeController::Config input_volume_controller_config; + struct AdaptiveDigitalConfig { + float headroom_db; + float max_gain_db; + float max_gain_change_db_per_second; + float max_output_noise_level_dbfs; + } adaptive_digital_config; + }; + protected: // Overridden in a mock. virtual void InitializeLocked() @@ -161,7 +173,7 @@ class AudioProcessingImpl : public AudioProcessing { FRIEND_TEST_ALL_PREFIXES(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules); FRIEND_TEST_ALL_PREFIXES( - AudioProcessingImplInputVolumeControllerExperimentParametrizedTest, + AudioProcessingImplGainController2FieldTrialParametrizedTest, ConfigAdjustedWhenExperimentEnabled); void set_stream_analog_level_locked(int level) @@ -192,10 +204,10 @@ class AudioProcessingImpl : public AudioProcessing { const bool use_setup_specific_default_aec3_config_; // TODO(bugs.webrtc.org/7494): Remove when the linked field trial is removed. - // Override base on the "WebRTC-Audio-InputVolumeControllerExperiment" field - // trial for the AGC2 input volume controller configuration. - const absl::optional - input_volume_controller_config_override_; + // Override based on the "WebRTC-Audio-GainController2" field trial for the + // AGC2 input volume controller and adaptive digital controller configuration. + const absl::optional + gain_controller2_config_override_; const bool use_denormal_disabler_; diff --git a/modules/audio_processing/audio_processing_impl_unittest.cc b/modules/audio_processing/audio_processing_impl_unittest.cc index 7a45c45b90..b394e93ec1 100644 --- a/modules/audio_processing/audio_processing_impl_unittest.cc +++ b/modules/audio_processing/audio_processing_impl_unittest.cc @@ -1235,10 +1235,12 @@ TEST(AudioProcessingImplTest, EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigAdjustedWhenExperimentEnabledAndAgc1AnalogEnabled) { + constexpr AudioProcessing::Config::GainController2::AdaptiveDigital + kDefaultAdaptiveDigitalConfig; webrtc::test::ScopedFieldTrials field_trials( - "WebRTC-Audio-InputVolumeControllerExperiment/" + "WebRTC-Audio-GainController2/" "Enabled," "enable_clipping_predictor:true," "clipped_level_min:20," @@ -1249,7 +1251,11 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, "target_range_min_dbfs:-70," "update_input_volume_wait_frames:80," "speech_probability_threshold:0.9," - "speech_ratio_threshold:1.0/"); + "speech_ratio_threshold:1.0," + "headroom_db:10," + "max_gain_db:20," + "max_gain_change_db_per_second:3," + "max_output_noise_level_dbfs:-40/"); AudioProcessingBuilderForTesting apm_builder; @@ -1275,6 +1281,8 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, EXPECT_TRUE(adjusted_config.gain_controller2.enabled); EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled); EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled); + EXPECT_NE(adjusted_config.gain_controller2.adaptive_digital, + kDefaultAdaptiveDigitalConfig); // Change config back and compare. adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled; @@ -1285,14 +1293,18 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, config.gain_controller2.adaptive_digital.enabled; adjusted_config.gain_controller2.input_volume_controller.enabled = config.gain_controller2.input_volume_controller.enabled; + adjusted_config.gain_controller2.adaptive_digital = + config.gain_controller2.adaptive_digital; EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString())); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigAdjustedWhenExperimentEnabledAndHybridAgcEnabled) { + constexpr AudioProcessing::Config::GainController2::AdaptiveDigital + kDefaultAdaptiveDigitalConfig; webrtc::test::ScopedFieldTrials field_trials( - "WebRTC-Audio-InputVolumeControllerExperiment/" + "WebRTC-Audio-GainController2/" "Enabled," "enable_clipping_predictor:true," "clipped_level_min:20," @@ -1303,7 +1315,11 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, "target_range_min_dbfs:-70," "update_input_volume_wait_frames:80," "speech_probability_threshold:0.9," - "speech_ratio_threshold:1.0/"); + "speech_ratio_threshold:1.0," + "headroom_db:10," + "max_gain_db:20," + "max_gain_change_db_per_second:3," + "max_output_noise_level_dbfs:-40/"); AudioProcessingBuilderForTesting apm_builder; @@ -1331,6 +1347,8 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, EXPECT_TRUE(adjusted_config.gain_controller2.enabled); EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled); EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled); + EXPECT_NE(adjusted_config.gain_controller2.adaptive_digital, + kDefaultAdaptiveDigitalConfig); // Change config back and compare. adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled; @@ -1341,14 +1359,16 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, config.gain_controller2.adaptive_digital.enabled; adjusted_config.gain_controller2.input_volume_controller.enabled = config.gain_controller2.input_volume_controller.enabled; + adjusted_config.gain_controller2.adaptive_digital = + config.gain_controller2.adaptive_digital; EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString())); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigNotAdjustedWhenExperimentEnabledAndAgc1AnalogNotEnabled) { webrtc::test::ScopedFieldTrials field_trials( - "WebRTC-Audio-InputVolumeControllerExperiment/" + "WebRTC-Audio-GainController2/" "Enabled," "enable_clipping_predictor:true," "clipped_level_min:20," @@ -1359,7 +1379,11 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, "target_range_min_dbfs:-70," "update_input_volume_wait_frames:80," "speech_probability_threshold:0.9," - "speech_ratio_threshold:1.0/"); + "speech_ratio_threshold:1.0," + "headroom_db:10," + "max_gain_db:20," + "max_gain_change_db_per_second:3," + "max_output_noise_level_dbfs:-40/"); AudioProcessingBuilderForTesting apm_builder; @@ -1393,10 +1417,10 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString())); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigNotAdjustedWhenExperimentEnabledAndHybridAgcNotEnabled) { webrtc::test::ScopedFieldTrials field_trials( - "WebRTC-Audio-InputVolumeControllerExperiment/" + "WebRTC-Audio-GainController2/" "Enabled," "enable_clipping_predictor:true," "clipped_level_min:20," @@ -1407,7 +1431,11 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, "target_range_min_dbfs:-70," "update_input_volume_wait_frames:80," "speech_probability_threshold:0.9," - "speech_ratio_threshold:1.0/"); + "speech_ratio_threshold:1.0," + "headroom_db:10," + "max_gain_db:20," + "max_gain_change_db_per_second:3," + "max_output_noise_level_dbfs:-40/"); AudioProcessingBuilderForTesting apm_builder; @@ -1443,7 +1471,7 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString())); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigNotAdjustedWhenExperimentNotEnabledAndAgc1AnalogEnabled) { AudioProcessingBuilderForTesting apm_builder; @@ -1477,7 +1505,7 @@ TEST(AudioProcessingImplInputVolumeControllerExperimentTest, EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString())); } -TEST(AudioProcessingImplInputVolumeControllerExperimentTest, +TEST(AudioProcessingImplGainController2FieldTrialTest, ConfigNotAdjustedWhenExperimentNotEnabledAndHybridAgcEnabled) { AudioProcessingBuilderForTesting apm_builder;