diff --git a/modules/audio_processing/agc2/input_volume_controller.cc b/modules/audio_processing/agc2/input_volume_controller.cc index ef03aaad4a..d82d15c342 100644 --- a/modules/audio_processing/agc2/input_volume_controller.cc +++ b/modules/audio_processing/agc2/input_volume_controller.cc @@ -32,7 +32,6 @@ constexpr int kLevelQuantizationSlack = 25; constexpr int kMaxMicLevel = 255; static_assert(kGainMapSize > kMaxMicLevel, "gain map too small"); -constexpr int kMinMicLevel = 12; // Prevent very large microphone level changes. constexpr int kMaxResidualGainChange = 15; @@ -49,31 +48,29 @@ Agc1ClippingPredictorConfig CreateClippingPredictorConfig(bool enabled) { return config; } -// If the "WebRTC-Audio-2ndAgcMinMicLevelExperiment" field trial is specified, -// parses it and returns a value between 0 and 255 depending on the field-trial -// string. Returns an unspecified value if the field trial is not specified, if -// disabled or if it cannot be parsed. Example: -// 'WebRTC-Audio-2ndAgcMinMicLevelExperiment/Enabled-80' => returns 80. -absl::optional GetMinMicLevelOverride() { - constexpr char kMinMicLevelFieldTrial[] = - "WebRTC-Audio-2ndAgcMinMicLevelExperiment"; - if (!webrtc::field_trial::IsEnabled(kMinMicLevelFieldTrial)) { - return absl::nullopt; +// Returns the minimum input volume to recommend. +// If the "WebRTC-Audio-Agc2-MinInputVolume" field trial is specified, parses it +// and returns the value specified after "Enabled-" if valid - i.e., in the +// range 0-255. Otherwise returns the default value. +// Example: +// "WebRTC-Audio-Agc2-MinInputVolume/Enabled-80" => returns 80. +int GetMinInputVolume() { + constexpr int kDefaultMinInputVolume = 12; + constexpr char kFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume"; + if (!webrtc::field_trial::IsEnabled(kFieldTrial)) { + return kDefaultMinInputVolume; } - const auto field_trial_string = - webrtc::field_trial::FindFullName(kMinMicLevelFieldTrial); - int min_mic_level = -1; - sscanf(field_trial_string.c_str(), "Enabled-%d", &min_mic_level); - if (min_mic_level >= 0 && min_mic_level <= 255) { - return min_mic_level; - } else { - RTC_LOG(LS_WARNING) << "[agc] Invalid parameter for " - << kMinMicLevelFieldTrial << ", ignored."; - return absl::nullopt; + std::string field_trial_str = webrtc::field_trial::FindFullName(kFieldTrial); + int min_input_volume = -1; + sscanf(field_trial_str.c_str(), "Enabled-%d", &min_input_volume); + if (min_input_volume >= 0 && min_input_volume <= 255) { + return min_input_volume; } + RTC_LOG(LS_WARNING) << "Invalid volume for " << kFieldTrial << ", ignored."; + return kDefaultMinInputVolume; } -int LevelFromGainError(int gain_error, int level, int min_mic_level) { +int LevelFromGainError(int gain_error, int level, int min_input_volume) { RTC_DCHECK_GE(level, 0); RTC_DCHECK_LE(level, kMaxMicLevel); if (gain_error == 0) { @@ -88,7 +85,7 @@ int LevelFromGainError(int gain_error, int level, int min_mic_level) { } } else { while (kGainMap[new_level] - kGainMap[level] > gain_error && - new_level > min_mic_level) { + new_level > min_input_volume) { --new_level; } } @@ -154,11 +151,11 @@ int GetSpeechLevelErrorDb(float speech_level_dbfs, MonoInputVolumeController::MonoInputVolumeController( int clipped_level_min, - int min_mic_level, + int min_input_volume, int update_input_volume_wait_frames, float speech_probability_threshold, float speech_ratio_threshold) - : min_mic_level_(min_mic_level), + : min_input_volume_(min_input_volume), max_level_(kMaxMicLevel), clipped_level_min_(clipped_level_min), update_input_volume_wait_frames_( @@ -167,8 +164,8 @@ MonoInputVolumeController::MonoInputVolumeController( speech_ratio_threshold_(speech_ratio_threshold) { RTC_DCHECK_GE(clipped_level_min_, 0); RTC_DCHECK_LE(clipped_level_min_, 255); - RTC_DCHECK_GE(min_mic_level_, 0); - RTC_DCHECK_LE(min_mic_level_, 255); + RTC_DCHECK_GE(min_input_volume_, 0); + RTC_DCHECK_LE(min_input_volume_, 255); RTC_DCHECK_GE(update_input_volume_wait_frames_, 0); RTC_DCHECK_GE(speech_probability_threshold_, 0.0f); RTC_DCHECK_LE(speech_probability_threshold_, 1.0f); @@ -331,8 +328,8 @@ int MonoInputVolumeController::CheckVolumeAndReset() { } RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level; - if (level < min_mic_level_) { - level = min_mic_level_; + if (level < min_input_volume_) { + level = min_input_volume_; RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level; recommended_input_volume_ = level; } @@ -357,13 +354,13 @@ void MonoInputVolumeController::UpdateInputVolume(int rms_error_dbfs) { return; } - SetLevel(LevelFromGainError(residual_gain, level_, min_mic_level_)); + SetLevel(LevelFromGainError(residual_gain, level_, min_input_volume_)); } InputVolumeController::InputVolumeController(int num_capture_channels, const Config& config) : num_capture_channels_(num_capture_channels), - min_mic_level_override_(GetMinMicLevelOverride()), + min_input_volume_(GetMinInputVolume()), capture_output_used_(true), clipped_level_step_(config.clipped_level_step), clipped_ratio_threshold_(config.clipped_ratio_threshold), @@ -381,16 +378,12 @@ InputVolumeController::InputVolumeController(int num_capture_channels, target_range_max_dbfs_(config.target_range_max_dbfs), target_range_min_dbfs_(config.target_range_min_dbfs), channel_controllers_(num_capture_channels) { - const int min_mic_level = min_mic_level_override_.value_or(kMinMicLevel); - RTC_LOG(LS_INFO) << "[agc] Input volume controller enabled"; - RTC_LOG(LS_INFO) << "[agc] Min mic level: " << min_mic_level - << " (overridden: " - << (min_mic_level_override_.has_value() ? "yes" : "no") - << ")"; - + RTC_LOG(LS_INFO) + << "[agc] Input volume controller enabled (min input volume: " + << min_input_volume_ << ")"; for (auto& controller : channel_controllers_) { controller = std::make_unique( - config.clipped_level_min, min_mic_level, + config.clipped_level_min, min_input_volume_, config.update_input_volume_wait_frames, config.speech_probability_threshold, config.speech_ratio_threshold); } @@ -551,9 +544,9 @@ void InputVolumeController::AggregateChannelLevels() { } } - if (min_mic_level_override_.has_value() && new_recommended_input_volume > 0) { + if (new_recommended_input_volume > 0) { new_recommended_input_volume = - std::max(new_recommended_input_volume, *min_mic_level_override_); + std::max(new_recommended_input_volume, min_input_volume_); } recommended_input_volume_ = new_recommended_input_volume; diff --git a/modules/audio_processing/agc2/input_volume_controller.h b/modules/audio_processing/agc2/input_volume_controller.h index 2cd764e6ee..e898ba0e34 100644 --- a/modules/audio_processing/agc2/input_volume_controller.h +++ b/modules/audio_processing/agc2/input_volume_controller.h @@ -143,8 +143,8 @@ class InputVolumeController final { const int num_capture_channels_; - // If not empty, the value is used to override the minimum input volume. - const absl::optional min_mic_level_override_; + // Minimum input volume that can be recommended. + const int min_input_volume_; // TODO(bugs.webrtc.org/7494): Create a separate member for the applied input // volume. @@ -220,7 +220,7 @@ class MonoInputVolumeController { int clipped_level_min() const { return clipped_level_min_; } // Only used for testing. - int min_mic_level() const { return min_mic_level_; } + int min_input_volume() const { return min_input_volume_; } private: // Sets a new input volume, after first checking that it hasn't been updated @@ -238,7 +238,7 @@ class MonoInputVolumeController { // action and cache the updated level. void UpdateInputVolume(int rms_error_dbfs); - const int min_mic_level_; + const int min_input_volume_; int level_ = 0; int max_level_; diff --git a/modules/audio_processing/agc2/input_volume_controller_unittest.cc b/modules/audio_processing/agc2/input_volume_controller_unittest.cc index 7faa260190..f950e611de 100644 --- a/modules/audio_processing/agc2/input_volume_controller_unittest.cc +++ b/modules/audio_processing/agc2/input_volume_controller_unittest.cc @@ -120,34 +120,32 @@ void CallPreProcessAudioBuffer(int num_calls, } } -constexpr char kMinMicLevelFieldTrial[] = - "WebRTC-Audio-2ndAgcMinMicLevelExperiment"; +constexpr char kMinInputVolumeFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume"; -std::string GetAgcMinMicLevelExperimentFieldTrial(const std::string& value) { +std::string GetAgcMinInputVolumeFieldTrial(const std::string& value) { char field_trial_buffer[64]; rtc::SimpleStringBuilder builder(field_trial_buffer); - builder << kMinMicLevelFieldTrial << "/" << value << "/"; + builder << kMinInputVolumeFieldTrial << "/" << value << "/"; return builder.str(); } -std::string GetAgcMinMicLevelExperimentFieldTrialEnabled( +std::string GetAgcMinInputVolumeFieldTrialEnabled( int enabled_value, const std::string& suffix = "") { RTC_DCHECK_GE(enabled_value, 0); RTC_DCHECK_LE(enabled_value, 255); char field_trial_buffer[64]; rtc::SimpleStringBuilder builder(field_trial_buffer); - builder << kMinMicLevelFieldTrial << "/Enabled-" << enabled_value << suffix + builder << kMinInputVolumeFieldTrial << "/Enabled-" << enabled_value << suffix << "/"; return builder.str(); } -std::string GetAgcMinMicLevelExperimentFieldTrial( - absl::optional min_mic_level) { - if (min_mic_level.has_value()) { - return GetAgcMinMicLevelExperimentFieldTrialEnabled(*min_mic_level); +std::string GetAgcMinInputVolumeFieldTrial(absl::optional volume) { + if (volume.has_value()) { + return GetAgcMinInputVolumeFieldTrialEnabled(*volume); } - return GetAgcMinMicLevelExperimentFieldTrial("Disabled"); + return GetAgcMinInputVolumeFieldTrial("Disabled"); } // (Over)writes `samples_value` for the samples in `audio_buffer`. @@ -382,7 +380,7 @@ class InputVolumeControllerParametrizedTest : public ::testing::TestWithParam> { protected: InputVolumeControllerParametrizedTest() - : field_trials_(GetAgcMinMicLevelExperimentFieldTrial(GetParam())) {} + : field_trials_(GetAgcMinInputVolumeFieldTrial(GetParam())) {} bool IsMinMicLevelOverridden() const { return GetParam().has_value(); } int GetMinMicLevel() const { return GetParam().value_or(kMinMicLevel); } @@ -573,34 +571,30 @@ TEST_P(InputVolumeControllerParametrizedTest, EXPECT_EQ(65, helper.manager.recommended_analog_level()); } -// Checks that, when the min mic level override is not specified, AGC ramps up -// towards the minimum mic level after the mic level is manually set below the -// minimum gain to enforce. +// Checks that the minimum input volume is enforced during the upward adjustment +// of the input volume. TEST_P(InputVolumeControllerParametrizedTest, - RecoveryAfterManualLevelChangeBelowMinWithoutMinMicLevelOverride) { - if (IsMinMicLevelOverridden()) { - GTEST_SKIP() << "Skipped. Min mic level overridden."; - } - + EnforceMinInputVolumeDuringUpwardsAdjustment) { InputVolumeControllerTestHelper helper; helper.CallAgcSequence(kInitialInputVolume, kHighSpeechProbability, kSpeechLevel); - // Manual change below min, but strictly positive, otherwise AGC won't take - // any action. + // Manual change below min, but strictly positive, otherwise no action will be + // taken. helper.manager.set_stream_analog_level(1); helper.CallProcess(/*num_calls=*/1, kHighSpeechProbability, -17.0f); - EXPECT_EQ(1, helper.manager.recommended_analog_level()); - // Continues working as usual afterwards. + // Trigger an upward adjustment of the input volume. + EXPECT_EQ(helper.manager.recommended_analog_level(), GetMinMicLevel()); helper.CallProcess(/*num_calls=*/1, kHighSpeechProbability, -29.0f); - EXPECT_EQ(1, helper.manager.recommended_analog_level()); - + EXPECT_EQ(helper.manager.recommended_analog_level(), GetMinMicLevel()); helper.CallProcess(/*num_calls=*/1, kHighSpeechProbability, -48.0f); - EXPECT_EQ(10, helper.manager.recommended_analog_level()); + EXPECT_EQ(helper.manager.recommended_analog_level(), GetMinMicLevel()); - helper.CallProcess(/*num_calls=*/1, kHighSpeechProbability, -38.0f); - EXPECT_EQ(16, helper.manager.recommended_analog_level()); + // After a number of consistently low speech level observations, the input + // volume is eventually raised above the minimum. + helper.CallProcess(/*num_calls=*/10, kHighSpeechProbability, -38.0f); + EXPECT_GT(helper.manager.recommended_analog_level(), GetMinMicLevel()); } // Checks that, when the min mic level override is specified, AGC immediately @@ -608,10 +602,6 @@ TEST_P(InputVolumeControllerParametrizedTest, // minimum gain to enforce. TEST_P(InputVolumeControllerParametrizedTest, RecoveryAfterManualLevelChangeBelowMin) { - if (!IsMinMicLevelOverridden()) { - GTEST_SKIP() << "Skipped. Min mic level not overridden."; - } - InputVolumeControllerTestHelper helper; helper.CallAgcSequence(kInitialInputVolume, kHighSpeechProbability, kSpeechLevel); @@ -783,18 +773,19 @@ TEST_P(InputVolumeControllerParametrizedTest, TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentDefault) { std::unique_ptr manager = CreateInputVolumeController( kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames); - EXPECT_EQ(manager->channel_controllers_[0]->min_mic_level(), kMinMicLevel); + EXPECT_EQ(manager->channel_controllers_[0]->min_input_volume(), kMinMicLevel); } TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentDisabled) { for (const std::string& field_trial_suffix : {"", "_20220210"}) { test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrial("Disabled" + field_trial_suffix)); + GetAgcMinInputVolumeFieldTrial("Disabled" + field_trial_suffix)); std::unique_ptr manager = CreateInputVolumeController(kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames); - EXPECT_EQ(manager->channel_controllers_[0]->min_mic_level(), kMinMicLevel); + EXPECT_EQ(manager->channel_controllers_[0]->min_input_volume(), + kMinMicLevel); } } @@ -802,20 +793,20 @@ TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentDisabled) { // ignored. TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentOutOfRangeAbove) { test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrial("Enabled-256")); + GetAgcMinInputVolumeFieldTrial("Enabled-256")); std::unique_ptr manager = CreateInputVolumeController( kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames); - EXPECT_EQ(manager->channel_controllers_[0]->min_mic_level(), kMinMicLevel); + EXPECT_EQ(manager->channel_controllers_[0]->min_input_volume(), kMinMicLevel); } // Checks that a field-trial parameter outside of the valid range [0,255] is // ignored. TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentOutOfRangeBelow) { test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrial("Enabled--1")); + GetAgcMinInputVolumeFieldTrial("Enabled--1")); std::unique_ptr manager = CreateInputVolumeController( kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames); - EXPECT_EQ(manager->channel_controllers_[0]->min_mic_level(), kMinMicLevel); + EXPECT_EQ(manager->channel_controllers_[0]->min_input_volume(), kMinMicLevel); } // Verifies that a valid experiment changes the minimum microphone level. The @@ -825,14 +816,13 @@ TEST(InputVolumeControllerTest, AgcMinMicLevelExperimentEnabled50) { constexpr int kMinMicLevelOverride = 50; for (const std::string& field_trial_suffix : {"", "_20220210"}) { SCOPED_TRACE(field_trial_suffix); - test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride, - field_trial_suffix)); + test::ScopedFieldTrials field_trial(GetAgcMinInputVolumeFieldTrialEnabled( + kMinMicLevelOverride, field_trial_suffix)); std::unique_ptr manager = CreateInputVolumeController(kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames); - EXPECT_EQ(manager->channel_controllers_[0]->min_mic_level(), + EXPECT_EQ(manager->channel_controllers_[0]->min_input_volume(), kMinMicLevelOverride); } } @@ -858,7 +848,7 @@ TEST(InputVolumeControllerTest, std::unique_ptr manager_with_override; { test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride)); + GetAgcMinInputVolumeFieldTrialEnabled(kMinMicLevelOverride)); manager_with_override = factory(); } @@ -915,7 +905,7 @@ TEST(InputVolumeControllerTest, std::unique_ptr manager_with_override; { test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride)); + GetAgcMinInputVolumeFieldTrialEnabled(kMinMicLevelOverride)); manager_with_override = factory(); } @@ -976,7 +966,7 @@ TEST(InputVolumeControllerTest, kMinMicLevelOverride, "Use a lower override value."); test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride)); + GetAgcMinInputVolumeFieldTrialEnabled(kMinMicLevelOverride)); manager_with_override = factory(); } @@ -1041,7 +1031,7 @@ TEST(InputVolumeControllerTest, kMinMicLevelOverride, "Use a lower override value."); test::ScopedFieldTrials field_trial( - GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride)); + GetAgcMinInputVolumeFieldTrialEnabled(kMinMicLevelOverride)); manager_with_override = factory(); }