From ebf4552c8f72d93cc4da92259c041f0b8a104518 Mon Sep 17 00:00:00 2001 From: henrika Date: Mon, 4 Nov 2019 13:59:21 +0100 Subject: [PATCH] Adds WebRTC-Audio-AgcMinMicLevelExperiment to AGC1 Bug: webrtc:11065 Change-Id: Id07ebab7bfa12980187a5847d4f11c8a57450147 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158784 Commit-Queue: Henrik Andreassson Reviewed-by: Minyue Li Cr-Commit-Position: refs/heads/master@{#29681} --- modules/audio_processing/agc/BUILD.gn | 2 + .../agc/agc_manager_direct.cc | 44 ++++++++++++--- .../audio_processing/agc/agc_manager_direct.h | 6 ++ .../agc/agc_manager_direct_unittest.cc | 56 +++++++++++++++++++ 4 files changed, 100 insertions(+), 8 deletions(-) diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn index 3214f012c0..05eb42d143 100644 --- a/modules/audio_processing/agc/BUILD.gn +++ b/modules/audio_processing/agc/BUILD.gn @@ -32,6 +32,7 @@ rtc_library("agc") { "../../../rtc_base:logging", "../../../rtc_base:macromagic", "../../../rtc_base:safe_minmax", + "../../../system_wrappers:field_trial", "../../../system_wrappers:metrics", "../agc2:level_estimation_agc", "../vad", @@ -109,6 +110,7 @@ if (rtc_include_tests) { ":gain_control_interface", ":level_estimation", "..:mocks", + "../../../test:field_trial", "../../../test:fileutils", "../../../test:test_support", "//testing/gtest", diff --git a/modules/audio_processing/agc/agc_manager_direct.cc b/modules/audio_processing/agc/agc_manager_direct.cc index f91356017b..cc0b482732 100644 --- a/modules/audio_processing/agc/agc_manager_direct.cc +++ b/modules/audio_processing/agc/agc_manager_direct.cc @@ -24,6 +24,7 @@ #include "rtc_base/checks.h" #include "rtc_base/logging.h" #include "rtc_base/numerics/safe_minmax.h" +#include "system_wrappers/include/field_trial.h" #include "system_wrappers/include/metrics.h" namespace webrtc { @@ -64,17 +65,42 @@ const int kSurplusCompressionGain = 6; constexpr size_t kMaxNumSamplesPerChannel = 1920; constexpr size_t kMaxNumChannels = 4; -int ClampLevel(int mic_level) { - return rtc::SafeClamp(mic_level, kMinMicLevel, kMaxMicLevel); +// Returns kMinMicLevel if no field trial exists or if it has been disabled. +// Returns a value between 0 and 255 depending on the field-trial string. +// Example: 'WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-80' => returns 80. +int GetMinMicLevel() { + RTC_LOG(LS_INFO) << "[agc] GetMinMicLevel"; + constexpr char kMinMicLevelFieldTrial[] = + "WebRTC-Audio-AgcMinMicLevelExperiment"; + if (!webrtc::field_trial::IsEnabled(kMinMicLevelFieldTrial)) { + RTC_LOG(LS_INFO) << "[agc] Using default min mic level: " << kMinMicLevel; + return kMinMicLevel; + } + 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) { + RTC_LOG(LS_INFO) << "[agc] Experimental min mic level: " << min_mic_level; + return min_mic_level; + } else { + RTC_LOG(LS_WARNING) << "[agc] Invalid parameter for " + << kMinMicLevelFieldTrial << ", ignored."; + return kMinMicLevel; + } } -int LevelFromGainError(int gain_error, int level) { +int ClampLevel(int mic_level, int min_mic_level) { + return rtc::SafeClamp(mic_level, min_mic_level, kMaxMicLevel); +} + +int LevelFromGainError(int gain_error, int level, int min_mic_level) { RTC_DCHECK_GE(level, 0); RTC_DCHECK_LE(level, kMaxMicLevel); if (gain_error == 0) { return level; } - // TODO(ajm): Could be made more efficient with a binary search. + int new_level = level; if (gain_error > 0) { while (kGainMap[new_level] - kGainMap[level] < gain_error && @@ -83,7 +109,7 @@ int LevelFromGainError(int gain_error, int level) { } } else { while (kGainMap[new_level] - kGainMap[level] > gain_error && - new_level > kMinMicLevel) { + new_level > min_mic_level) { --new_level; } } @@ -192,9 +218,10 @@ AgcManagerDirect::AgcManagerDirect(Agc* agc, capture_muted_(false), check_volume_on_next_process_(true), // Check at startup. startup_(true), + min_mic_level_(GetMinMicLevel()), use_agc2_level_estimation_(use_agc2_level_estimation), disable_digital_adaptive_(disable_digital_adaptive), - startup_min_level_(ClampLevel(startup_min_level)), + startup_min_level_(ClampLevel(startup_min_level, min_mic_level_)), clipped_level_min_(clipped_level_min), file_preproc_(new DebugFile("agc_preproc.pcm")), file_postproc_(new DebugFile("agc_postproc.pcm")) { @@ -210,6 +237,7 @@ AgcManagerDirect::AgcManagerDirect(Agc* agc, AgcManagerDirect::~AgcManagerDirect() {} int AgcManagerDirect::Initialize() { + RTC_DLOG(LS_INFO) << "AgcManagerDirect::Initialize"; max_level_ = kMaxMicLevel; max_compression_gain_ = kMaxCompressionGain; target_compression_ = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; @@ -415,7 +443,7 @@ int AgcManagerDirect::CheckVolumeAndReset() { } RTC_DLOG(LS_INFO) << "[agc] Initial GetMicVolume()=" << level; - int minLevel = startup_ ? startup_min_level_ : kMinMicLevel; + int minLevel = startup_ ? startup_min_level_ : min_mic_level_; if (level < minLevel) { level = minLevel; RTC_DLOG(LS_INFO) << "[agc] Initial volume too low, raising to " << level; @@ -477,7 +505,7 @@ void AgcManagerDirect::UpdateGain() { return; int old_level = level_; - SetLevel(LevelFromGainError(residual_gain, level_)); + SetLevel(LevelFromGainError(residual_gain, level_, min_mic_level_)); if (old_level != level_) { // level_ was updated by SetLevel; log the new value. RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.AgcSetLevel", level_, 1, diff --git a/modules/audio_processing/agc/agc_manager_direct.h b/modules/audio_processing/agc/agc_manager_direct.h index a637fca9a5..ddb14e5b51 100644 --- a/modules/audio_processing/agc/agc_manager_direct.h +++ b/modules/audio_processing/agc/agc_manager_direct.h @@ -74,6 +74,8 @@ class AgcManagerDirect final { FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital); + FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, + AgcMinMicLevelExperiment); // Dependency injection for testing. Don't delete |agc| as the memory is owned // by the manager. @@ -92,6 +94,9 @@ class AgcManagerDirect final { bool use_agc2_level_estimation, bool disable_digital_adaptive); + int min_mic_level() const { return min_mic_level_; } + int startup_min_level() const { return startup_min_level_; } + // Sets a new microphone level, after first checking that it hasn't been // updated by the user, in which case no action is taken. void SetLevel(int new_level); @@ -122,6 +127,7 @@ class AgcManagerDirect final { bool capture_muted_; bool check_volume_on_next_process_; bool startup_; + const int min_mic_level_; const bool use_agc2_level_estimation_; const bool disable_digital_adaptive_; int startup_min_level_; diff --git a/modules/audio_processing/agc/agc_manager_direct_unittest.cc b/modules/audio_processing/agc/agc_manager_direct_unittest.cc index 615a8d8a5f..faab5c0f8c 100644 --- a/modules/audio_processing/agc/agc_manager_direct_unittest.cc +++ b/modules/audio_processing/agc/agc_manager_direct_unittest.cc @@ -13,6 +13,7 @@ #include "modules/audio_processing/agc/gain_control.h" #include "modules/audio_processing/agc/mock_agc.h" #include "modules/audio_processing/include/mock_audio_processing.h" +#include "test/field_trial.h" #include "test/gmock.h" #include "test/gtest.h" @@ -31,6 +32,7 @@ const int kSamplesPerChannel = kSampleRateHz / 100; const int kInitialVolume = 128; constexpr int kClippedMin = 165; // Arbitrary, but different from the default. const float kAboveClippedThreshold = 0.2f; +const int kMinMicLevel = 12; class MockGainControl : public GainControl { public: @@ -722,4 +724,58 @@ TEST(AgcManagerDirectStandaloneTest, DisableDigitalDisablesDigital) { manager.Initialize(); } +TEST(AgcManagerDirectStandaloneTest, AgcMinMicLevelExperiment) { + auto agc_man = std::unique_ptr(new AgcManagerDirect( + nullptr, nullptr, nullptr, kInitialVolume, kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), kMinMicLevel); + EXPECT_EQ(agc_man->startup_min_level(), kInitialVolume); + { + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-AgcMinMicLevelExperiment/Disabled/"); + agc_man.reset(new AgcManagerDirect( + nullptr, nullptr, nullptr, kInitialVolume, kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), kMinMicLevel); + EXPECT_EQ(agc_man->startup_min_level(), kInitialVolume); + } + { + // Valid range of field-trial parameter is [0,255]. + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-256/"); + agc_man.reset(new AgcManagerDirect( + nullptr, nullptr, nullptr, kInitialVolume, kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), kMinMicLevel); + EXPECT_EQ(agc_man->startup_min_level(), kInitialVolume); + } + { + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled--1/"); + agc_man.reset(new AgcManagerDirect( + nullptr, nullptr, nullptr, kInitialVolume, kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), kMinMicLevel); + EXPECT_EQ(agc_man->startup_min_level(), kInitialVolume); + } + { + // Verify that a valid experiment changes the minimum microphone level. + // The start volume is larger than the min level and should therefore not + // be changed. + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); + agc_man.reset(new AgcManagerDirect( + nullptr, nullptr, nullptr, kInitialVolume, kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), 50); + EXPECT_EQ(agc_man->startup_min_level(), kInitialVolume); + } + { + // Use experiment to reduce the default minimum microphone level, start at + // a lower level and ensure that the startup level is increased to the min + // level set by the experiment. + test::ScopedFieldTrials field_trial( + "WebRTC-Audio-AgcMinMicLevelExperiment/Enabled-50/"); + agc_man.reset(new AgcManagerDirect(nullptr, nullptr, nullptr, 30, + kClippedMin, true, true)); + EXPECT_EQ(agc_man->min_mic_level(), 50); + EXPECT_EQ(agc_man->startup_min_level(), 50); + } +} + } // namespace webrtc