From 866caeb62ce56bf3a4332adefca52fe496106657 Mon Sep 17 00:00:00 2001 From: Alessio Bazzica Date: Tue, 19 Jul 2022 12:18:38 +0200 Subject: [PATCH] `AgcManagerDirect` ctor API and doc string improved Bug: chromium:1275566 Change-Id: Iedc8f5cbbf65fbf018da9df1aaa1f8ade1bbc063 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/268840 Reviewed-by: Hanna Silen Commit-Queue: Alessio Bazzica Cr-Commit-Position: refs/heads/main@{#37569} --- modules/audio_processing/agc/BUILD.gn | 1 + .../agc/agc_manager_direct.cc | 78 ++++------ .../audio_processing/agc/agc_manager_direct.h | 71 +++++----- .../agc/agc_manager_direct_unittest.cc | 134 +++++++++--------- .../audio_processing/audio_processing_impl.cc | 13 +- .../include/audio_processing.h | 2 + 6 files changed, 137 insertions(+), 162 deletions(-) diff --git a/modules/audio_processing/agc/BUILD.gn b/modules/audio_processing/agc/BUILD.gn index ade35af06a..1142f36d35 100644 --- a/modules/audio_processing/agc/BUILD.gn +++ b/modules/audio_processing/agc/BUILD.gn @@ -24,6 +24,7 @@ rtc_library("agc") { ":gain_control_interface", ":gain_map", ":level_estimation", + "..:api", "..:apm_logging", "..:audio_buffer", "..:audio_frame_view", diff --git a/modules/audio_processing/agc/agc_manager_direct.cc b/modules/audio_processing/agc/agc_manager_direct.cc index 93f38bcab0..be9a394cdf 100644 --- a/modules/audio_processing/agc/agc_manager_direct.cc +++ b/modules/audio_processing/agc/agc_manager_direct.cc @@ -53,8 +53,8 @@ constexpr int kSurplusCompressionGain = 6; // frames). constexpr int kClippingPredictorEvaluatorHistorySize = 500; -using ClippingPredictorConfig = AudioProcessing::Config::GainController1:: - AnalogGainController::ClippingPredictor; +using AnalogAgcConfig = + AudioProcessing::Config::GainController1::AnalogGainController; // Returns whether a fall-back solution to choose the maximum level should be // chosen. @@ -441,51 +441,35 @@ void MonoAgc::UpdateCompressor() { std::atomic AgcManagerDirect::instance_counter_(0); AgcManagerDirect::AgcManagerDirect( - Agc* agc, - int startup_min_level, - int clipped_level_min, - int clipped_level_step, - float clipped_ratio_threshold, - int clipped_wait_frames, - const ClippingPredictorConfig& clipping_config) - : AgcManagerDirect(/*num_capture_channels=*/1, - startup_min_level, - clipped_level_min, - /*disable_digital_adaptive=*/false, - clipped_level_step, - clipped_ratio_threshold, - clipped_wait_frames, - clipping_config) { + const AudioProcessing::Config::GainController1::AnalogGainController& + analog_config, + Agc* agc) + : AgcManagerDirect(/*num_capture_channels=*/1, analog_config) { RTC_DCHECK(channel_agcs_[0]); RTC_DCHECK(agc); channel_agcs_[0]->set_agc(agc); } -AgcManagerDirect::AgcManagerDirect( - int num_capture_channels, - int startup_min_level, - int clipped_level_min, - bool disable_digital_adaptive, - int clipped_level_step, - float clipped_ratio_threshold, - int clipped_wait_frames, - const ClippingPredictorConfig& clipping_config) +AgcManagerDirect::AgcManagerDirect(int num_capture_channels, + const AnalogAgcConfig& analog_config) : min_mic_level_override_(GetMinMicLevelOverride()), data_dumper_(new ApmDataDumper(instance_counter_.fetch_add(1) + 1)), use_min_channel_level_(!UseMaxAnalogChannelLevel()), num_capture_channels_(num_capture_channels), - disable_digital_adaptive_(disable_digital_adaptive), - frames_since_clipped_(clipped_wait_frames), + disable_digital_adaptive_(!analog_config.enable_digital_adaptive), + frames_since_clipped_(analog_config.clipped_wait_frames), capture_output_used_(true), - clipped_level_step_(clipped_level_step), - clipped_ratio_threshold_(clipped_ratio_threshold), - clipped_wait_frames_(clipped_wait_frames), + clipped_level_step_(analog_config.clipped_level_step), + clipped_ratio_threshold_(analog_config.clipped_ratio_threshold), + clipped_wait_frames_(analog_config.clipped_wait_frames), channel_agcs_(num_capture_channels), new_compressions_to_set_(num_capture_channels), clipping_predictor_( - CreateClippingPredictor(num_capture_channels, clipping_config)), - use_clipping_predictor_step_(!!clipping_predictor_ && - clipping_config.use_predicted_step), + CreateClippingPredictor(num_capture_channels, + analog_config.clipping_predictor)), + use_clipping_predictor_step_( + !!clipping_predictor_ && + analog_config.clipping_predictor.use_predicted_step), clipping_predictor_evaluator_(kClippingPredictorEvaluatorHistorySize), clipping_predictor_log_counter_(0), clipping_rate_log_(0.0f), @@ -499,15 +483,16 @@ AgcManagerDirect::AgcManagerDirect( ApmDataDumper* data_dumper_ch = ch == 0 ? data_dumper_.get() : nullptr; channel_agcs_[ch] = std::make_unique( - data_dumper_ch, startup_min_level, clipped_level_min, - disable_digital_adaptive_, min_mic_level); + data_dumper_ch, analog_config.startup_min_volume, + analog_config.clipped_level_min, disable_digital_adaptive_, + min_mic_level); } RTC_DCHECK(!channel_agcs_.empty()); - RTC_DCHECK_GT(clipped_level_step, 0); - RTC_DCHECK_LE(clipped_level_step, 255); - RTC_DCHECK_GT(clipped_ratio_threshold, 0.f); - RTC_DCHECK_LT(clipped_ratio_threshold, 1.f); - RTC_DCHECK_GT(clipped_wait_frames, 0); + RTC_DCHECK_GT(clipped_level_step_, 0); + RTC_DCHECK_LE(clipped_level_step_, 255); + RTC_DCHECK_GT(clipped_ratio_threshold_, 0.0f); + RTC_DCHECK_LT(clipped_ratio_threshold_, 1.0f); + RTC_DCHECK_GT(clipped_wait_frames_, 0); channel_agcs_[0]->ActivateLogging(); } @@ -529,22 +514,21 @@ void AgcManagerDirect::Initialize() { } void AgcManagerDirect::SetupDigitalGainControl( - GainControl* gain_control) const { - RTC_DCHECK(gain_control); - if (gain_control->set_mode(GainControl::kFixedDigital) != 0) { + GainControl& gain_control) const { + if (gain_control.set_mode(GainControl::kFixedDigital) != 0) { RTC_LOG(LS_ERROR) << "set_mode(GainControl::kFixedDigital) failed."; } const int target_level_dbfs = disable_digital_adaptive_ ? 0 : 2; - if (gain_control->set_target_level_dbfs(target_level_dbfs) != 0) { + if (gain_control.set_target_level_dbfs(target_level_dbfs) != 0) { RTC_LOG(LS_ERROR) << "set_target_level_dbfs() failed."; } const int compression_gain_db = disable_digital_adaptive_ ? 0 : kDefaultCompressionGain; - if (gain_control->set_compression_gain_db(compression_gain_db) != 0) { + if (gain_control.set_compression_gain_db(compression_gain_db) != 0) { RTC_LOG(LS_ERROR) << "set_compression_gain_db() failed."; } const bool enable_limiter = !disable_digital_adaptive_; - if (gain_control->enable_limiter(enable_limiter) != 0) { + if (gain_control.enable_limiter(enable_limiter) != 0) { RTC_LOG(LS_ERROR) << "enable_limiter() failed."; } } diff --git a/modules/audio_processing/agc/agc_manager_direct.h b/modules/audio_processing/agc/agc_manager_direct.h index dbf8616153..3c281b91cd 100644 --- a/modules/audio_processing/agc/agc_manager_direct.h +++ b/modules/audio_processing/agc/agc_manager_direct.h @@ -20,6 +20,7 @@ #include "modules/audio_processing/agc/clipping_predictor.h" #include "modules/audio_processing/agc/clipping_predictor_evaluator.h" #include "modules/audio_processing/audio_buffer.h" +#include "modules/audio_processing/include/audio_processing.h" #include "modules/audio_processing/logging/apm_data_dumper.h" #include "rtc_base/gtest_prod_util.h" @@ -28,53 +29,60 @@ namespace webrtc { class MonoAgc; class GainControl; -// Direct interface to use AGC to set volume and compression values. -// AudioProcessing uses this interface directly to integrate the callback-less -// AGC. -// -// This class is not thread-safe. +// Adaptive Gain Controller (AGC) that combines an analog and digital gain +// controller. The digital controller determines and applies the digital +// compression gain. The analog controller recommends what input volume (a.k.a., +// analog level) to use, handles input volume changes and input clipping. In +// particular, it handles input volume changes triggered by the user (e.g., +// input volume set to zero by a HW mute button). This class is not thread-safe. class AgcManagerDirect final { public: - // AgcManagerDirect will configure GainControl internally. The user is - // responsible for processing the audio using it after the call to Process. - // The operating range of startup_min_level is [12, 255] and any input value - // outside that range will be clamped. `clipped_level_step` is the amount - // the microphone level is lowered with every clipping event, limited to - // (0, 255]. `clipped_ratio_threshold` is the proportion of clipped - // samples required to declare a clipping event, limited to (0.f, 1.f). - // `clipped_wait_frames` is the time in frames to wait after a clipping event - // before checking again, limited to values higher than 0. + // Ctor. `num_capture_channels` specifies the number of channels for the audio + // passed to `AnalyzePreProcess()` and `Process()`. Clamps + // `analog_config.startup_min_level` in the [12, 255] range. AgcManagerDirect( int num_capture_channels, - int startup_min_level, - int clipped_level_min, - bool disable_digital_adaptive, - int clipped_level_step, - float clipped_ratio_threshold, - int clipped_wait_frames, - const AudioProcessing::Config::GainController1::AnalogGainController:: - ClippingPredictor& clipping_config); + const AudioProcessing::Config::GainController1::AnalogGainController& + analog_config); ~AgcManagerDirect(); AgcManagerDirect(const AgcManagerDirect&) = delete; AgcManagerDirect& operator=(const AgcManagerDirect&) = delete; void Initialize(); - void SetupDigitalGainControl(GainControl* gain_control) const; + // Configures `gain_control` to work as a fixed digital controller so that the + // adaptive part is only handled by this gain controller. Must be called if + // `gain_control` is also used to avoid the side-effects of running two AGCs. + void SetupDigitalGainControl(GainControl& gain_control) const; + + // Analyzes `audio` before `Process()` is called so that the analysis can be + // performed before external digital processing operations take place (e.g., + // echo cancellation). The analysis consists of input clipping detection and + // prediction (if enabled). void AnalyzePreProcess(const AudioBuffer* audio); + + // Processes `audio`. Chooses and applies a digital compression gain on each + // channel and chooses the new input volume to recommend. Undefined behavior + // if `AnalyzePreProcess()` is not called beforehand. void Process(const AudioBuffer* audio); // Call when the capture stream output has been flagged to be used/not-used. // If unused, the manager disregards all incoming audio. void HandleCaptureOutputUsedChange(bool capture_output_used); + float voice_probability() const; + // Returns the recommended input volume. int stream_analog_level() const { return stream_analog_level_; } + + // Sets the current input volume. void set_stream_analog_level(int level); + int num_channels() const { return num_capture_channels_; } - // If available, returns a new compression gain for the digital gain control. + // If available, returns the latest digital compression gain that has been + // applied. absl::optional GetDigitalComressionGain(); // Returns true if clipping prediction is enabled. @@ -109,17 +117,12 @@ class AgcManagerDirect final { FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectTest, UnusedClippingPredictionsProduceEqualAnalogLevels); - // Dependency injection for testing. Don't delete `agc` as the memory is owned - // by the manager. + // Ctor that creates a single channel AGC and by injecting `agc`. + // `agc` will be owned by this class; hence, do not delete it. AgcManagerDirect( - Agc* agc, - int startup_min_level, - int clipped_level_min, - int clipped_level_step, - float clipped_ratio_threshold, - int clipped_wait_frames, - const AudioProcessing::Config::GainController1::AnalogGainController:: - ClippingPredictor& clipping_config); + const AudioProcessing::Config::GainController1::AnalogGainController& + analog_config, + Agc* agc); void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel); diff --git a/modules/audio_processing/agc/agc_manager_direct_unittest.cc b/modules/audio_processing/agc/agc_manager_direct_unittest.cc index 3b11fe0471..52e6392bea 100644 --- a/modules/audio_processing/agc/agc_manager_direct_unittest.cc +++ b/modules/audio_processing/agc/agc_manager_direct_unittest.cc @@ -40,11 +40,11 @@ constexpr int kClippedLevelStep = 15; constexpr float kClippedRatioThreshold = 0.1f; constexpr int kClippedWaitFrames = 300; -constexpr AudioProcessing::Config::GainController1::AnalogGainController - kDefaultAnalogConfig{}; - +using AnalogAgcConfig = + AudioProcessing::Config::GainController1::AnalogGainController; using ClippingPredictorConfig = AudioProcessing::Config::GainController1:: AnalogGainController::ClippingPredictor; +constexpr AnalogAgcConfig kDefaultAnalogConfig{}; class MockGainControl : public GainControl { public: @@ -68,28 +68,24 @@ class MockGainControl : public GainControl { MOCK_METHOD(bool, stream_is_saturated, (), (const, override)); }; +// TODO(bugs.webrtc.org/12874): Remove and use designated initializers once +// fixed. std::unique_ptr CreateAgcManagerDirect( - int startup_min_level, - int clipped_level_step, - float clipped_ratio_threshold, - int clipped_wait_frames) { - return std::make_unique( - /*num_capture_channels=*/1, startup_min_level, kClippedMin, - /*disable_digital_adaptive=*/true, clipped_level_step, - clipped_ratio_threshold, clipped_wait_frames, - kDefaultAnalogConfig.clipping_predictor); -} - -std::unique_ptr CreateAgcManagerDirect( - int startup_min_level, + int startup_min_volume, int clipped_level_step, float clipped_ratio_threshold, int clipped_wait_frames, - const ClippingPredictorConfig& clipping_cfg) { - return std::make_unique( - /*num_capture_channels=*/1, startup_min_level, kClippedMin, - /*disable_digital_adaptive=*/true, clipped_level_step, - clipped_ratio_threshold, clipped_wait_frames, clipping_cfg); + const ClippingPredictorConfig& clipping_predictor_config = + kDefaultAnalogConfig.clipping_predictor) { + AnalogAgcConfig config; + config.startup_min_volume = startup_min_volume; + config.clipped_level_min = kClippedMin; + config.enable_digital_adaptive = false; + config.clipped_level_step = clipped_level_step; + config.clipped_ratio_threshold = clipped_ratio_threshold; + config.clipped_wait_frames = clipped_wait_frames; + config.clipping_predictor = clipping_predictor_config; + return std::make_unique(/*num_capture_channels=*/1, config); } // Calls `AnalyzePreProcess()` on `manager` `num_calls` times. `peak_ratio` is a @@ -185,6 +181,20 @@ void CallPreProcessAndProcess(int num_calls, } // namespace +// TODO(bugs.webrtc.org/12874): Use constexpr struct with designated +// initializers once fixed. +constexpr AnalogAgcConfig GetAnalogAgcTestConfig() { + AnalogAgcConfig config; + config.startup_min_volume = kInitialVolume; + config.clipped_level_min = kClippedMin; + config.enable_digital_adaptive = true; + config.clipped_level_step = kClippedLevelStep; + config.clipped_ratio_threshold = kClippedRatioThreshold; + config.clipped_wait_frames = kClippedWaitFrames; + config.clipping_predictor = kDefaultAnalogConfig.clipping_predictor; + return config; +}; + class AgcManagerDirectTestHelper { public: AgcManagerDirectTestHelper() @@ -197,16 +207,10 @@ class AgcManagerDirectTestHelper { audio(kNumChannels), audio_data(kNumChannels * kSamplesPerChannel, 0.0f), mock_agc(new MockAgc()), - manager(mock_agc, - kInitialVolume, - kClippedMin, - kClippedLevelStep, - kClippedRatioThreshold, - kClippedWaitFrames, - kDefaultAnalogConfig.clipping_predictor) { + manager(GetAnalogAgcTestConfig(), mock_agc) { ExpectInitialize(); manager.Initialize(); - manager.SetupDigitalGainControl(&mock_gain_control); + manager.SetupDigitalGainControl(mock_gain_control); for (size_t ch = 0; ch < kNumChannels; ++ch) { audio[ch] = &audio_data[ch * kSamplesPerChannel]; } @@ -947,11 +951,11 @@ TEST(AgcManagerDirectTest, DisableDigitalDisablesDigital) { EXPECT_CALL(mock_gain_control, set_compression_gain_db(0)); EXPECT_CALL(mock_gain_control, enable_limiter(false)); - std::unique_ptr manager = - CreateAgcManagerDirect(kInitialVolume, kClippedLevelStep, - kClippedRatioThreshold, kClippedWaitFrames); + AnalogAgcConfig config; + config.enable_digital_adaptive = false; + auto manager = std::make_unique(kNumChannels, config); manager->Initialize(); - manager->SetupDigitalGainControl(&mock_gain_control); + manager->SetupDigitalGainControl(mock_gain_control); } TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentDefault) { @@ -1075,12 +1079,14 @@ TEST(AgcManagerDirectTest, const auto factory = []() { // Use a large clipped level step to more quickly decrease the analog gain // with clipping. - auto controller = std::make_unique( - /*num_capture_channels=*/1, kInitialVolume, - kDefaultAnalogConfig.clipped_level_min, - /*disable_digital_adaptive=*/true, /*clipped_level_step=*/64, - kClippedRatioThreshold, kClippedWaitFrames, - kDefaultAnalogConfig.clipping_predictor); + AnalogAgcConfig config = kDefaultAnalogConfig; + config.startup_min_volume = kInitialVolume; + config.enable_digital_adaptive = false; + config.clipped_level_step = 64; + config.clipped_ratio_threshold = kClippedRatioThreshold; + config.clipped_wait_frames = kClippedWaitFrames; + auto controller = + std::make_unique(/*num_capture_channels=*/1, config); controller->Initialize(); controller->set_stream_analog_level(kInitialVolume); return controller; @@ -1181,11 +1187,9 @@ TEST(AgcManagerDirectTest, DisableClippingPredictorDoesNotLowerVolume) { AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels); - // TODO(bugs.webrtc.org/12874): Use designated initializers once fixed. - constexpr ClippingPredictorConfig kConfig{/*enabled=*/false}; - AgcManagerDirect manager(new ::testing::NiceMock(), kInitialVolume, - kClippedMin, kClippedLevelStep, - kClippedRatioThreshold, kClippedWaitFrames, kConfig); + AnalogAgcConfig config = GetAnalogAgcTestConfig(); + config.clipping_predictor.enabled = false; + AgcManagerDirect manager(config, new ::testing::NiceMock()); manager.Initialize(); manager.set_stream_analog_level(/*level=*/255); EXPECT_FALSE(manager.clipping_predictor_enabled()); @@ -1204,20 +1208,15 @@ TEST(AgcManagerDirectTest, UsedClippingPredictionsProduceLowerAnalogLevels) { AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels); - // TODO(bugs.webrtc.org/12874): Use designated initializers once fixed. - ClippingPredictorConfig config_with_prediction; - config_with_prediction.enabled = true; - config_with_prediction.use_predicted_step = true; - ClippingPredictorConfig config_without_prediction; - config_without_prediction.enabled = false; - AgcManagerDirect manager_with_prediction( - new ::testing::NiceMock(), kInitialVolume, kClippedMin, - kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames, - config_with_prediction); + AnalogAgcConfig config_with_prediction = GetAnalogAgcTestConfig(); + config_with_prediction.clipping_predictor.enabled = true; + config_with_prediction.clipping_predictor.use_predicted_step = true; + AnalogAgcConfig config_without_prediction = GetAnalogAgcTestConfig(); + config_without_prediction.clipping_predictor.enabled = false; + AgcManagerDirect manager_with_prediction(config_with_prediction, + new ::testing::NiceMock()); AgcManagerDirect manager_without_prediction( - new ::testing::NiceMock(), kInitialVolume, kClippedMin, - kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames, - config_without_prediction); + config_without_prediction, new ::testing::NiceMock()); manager_with_prediction.Initialize(); manager_without_prediction.Initialize(); @@ -1307,20 +1306,15 @@ TEST(AgcManagerDirectTest, UnusedClippingPredictionsProduceEqualAnalogLevels) { AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels, kSampleRateHz, kNumChannels); - // TODO(bugs.webrtc.org/12874): Use designated initializers once fixed. - ClippingPredictorConfig config_with_prediction; - config_with_prediction.enabled = true; - config_with_prediction.use_predicted_step = false; - ClippingPredictorConfig config_without_prediction; - config_without_prediction.enabled = false; - AgcManagerDirect manager_with_prediction( - new ::testing::NiceMock(), kInitialVolume, kClippedMin, - kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames, - config_with_prediction); + AnalogAgcConfig config_with_prediction = GetAnalogAgcTestConfig(); + config_with_prediction.clipping_predictor.enabled = true; + config_with_prediction.clipping_predictor.use_predicted_step = false; + AnalogAgcConfig config_without_prediction = GetAnalogAgcTestConfig(); + config_without_prediction.clipping_predictor.enabled = false; + AgcManagerDirect manager_with_prediction(config_with_prediction, + new ::testing::NiceMock()); AgcManagerDirect manager_without_prediction( - new ::testing::NiceMock(), kInitialVolume, kClippedMin, - kClippedLevelStep, kClippedRatioThreshold, kClippedWaitFrames, - config_without_prediction); + config_without_prediction, new ::testing::NiceMock()); constexpr int kInitialLevel = 255; constexpr float kClippingPeakRatio = 1.0f; diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index b7d23409da..cb0c4d6b6c 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -1889,22 +1889,13 @@ void AudioProcessingImpl::InitializeGainController1() { stream_analog_level = submodules_.agc_manager->stream_analog_level(); } submodules_.agc_manager.reset(new AgcManagerDirect( - num_proc_channels(), - config_.gain_controller1.analog_gain_controller.startup_min_volume, - config_.gain_controller1.analog_gain_controller.clipped_level_min, - !config_.gain_controller1.analog_gain_controller - .enable_digital_adaptive, - config_.gain_controller1.analog_gain_controller.clipped_level_step, - config_.gain_controller1.analog_gain_controller.clipped_ratio_threshold, - config_.gain_controller1.analog_gain_controller.clipped_wait_frames, - config_.gain_controller1.analog_gain_controller.clipping_predictor)); + num_proc_channels(), config_.gain_controller1.analog_gain_controller)); if (re_creation) { submodules_.agc_manager->set_stream_analog_level(stream_analog_level); } } submodules_.agc_manager->Initialize(); - submodules_.agc_manager->SetupDigitalGainControl( - submodules_.gain_control.get()); + submodules_.agc_manager->SetupDigitalGainControl(*submodules_.gain_control); submodules_.agc_manager->HandleCaptureOutputUsedChange( capture_.capture_output_used); } diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h index 1088f9b46d..6e50f21eeb 100644 --- a/modules/audio_processing/include/audio_processing.h +++ b/modules/audio_processing/include/audio_processing.h @@ -286,10 +286,12 @@ class RTC_EXPORT AudioProcessing : public rtc::RefCountInterface { // Enables the analog gain controller functionality. struct AnalogGainController { bool enabled = true; + // TODO(bugs.webrtc.org/1275566): Describe `startup_min_volume`. int startup_min_volume = kAgcStartupMinVolume; // Lowest analog microphone level that will be applied in response to // clipping. int clipped_level_min = kClippedLevelMin; + // If true, an adaptive digital gain is applied. bool enable_digital_adaptive = true; // Amount the microphone level is lowered with every clipping event. // Limited to (0, 255].