AGC2 dummy module: fixed gain param, APM integration, audioproc_f adaptation

In preparation of coming CLs that will add an AGC interface to make the
gain controller injectable.

This CL simplifies AGC2 (dummy sub-module of audioproc_f) since it only
implements the fixed digital mode with hard-clipping - i.e., no limiter
is used.
The AGC2 config now includes the fixed gain to apply and audioproc_f
has been adapted accordingly.
Finally, this CL slightly simplifies the AGC2 integration into APM.

This CL is a continuation of https://codereview.webrtc.org/2995043002/

Bug: webrtc:7494
Change-Id: I3d554ea4dc6208928352059feb14987edabf14c7
Reviewed-on: https://webrtc-review.googlesource.com/4661
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20278}
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index dd2ded6..dd63e2f 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -108,8 +108,6 @@
     "agc/loudness_histogram.h",
     "agc/utility.cc",
     "agc/utility.h",
-    "agc2/digital_gain_applier.cc",
-    "agc2/digital_gain_applier.h",
     "agc2/gain_controller2.cc",
     "agc2/gain_controller2.h",
     "audio_buffer.cc",
diff --git a/modules/audio_processing/agc2/digital_gain_applier.cc b/modules/audio_processing/agc2/digital_gain_applier.cc
deleted file mode 100644
index ec706ec..0000000
--- a/modules/audio_processing/agc2/digital_gain_applier.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "modules/audio_processing/agc2/digital_gain_applier.h"
-
-#include <algorithm>
-
-namespace webrtc {
-namespace {
-
-constexpr float kMaxSampleValue = 32767.0f;
-constexpr float kMinSampleValue = -32767.0f;
-
-}  // namespace
-
-DigitalGainApplier::DigitalGainApplier() = default;
-
-void DigitalGainApplier::Process(float gain, rtc::ArrayView<float> samples) {
-  if (gain == 1.f) { return; }
-  for (auto& v : samples) { v *= gain; }
-  LimitToAllowedRange(samples);
-}
-
-void DigitalGainApplier::LimitToAllowedRange(rtc::ArrayView<float> x) {
-  for (auto& v : x) {
-    v = std::max(kMinSampleValue, v);
-    v = std::min(kMaxSampleValue, v);
-  }
-}
-
-}  // namespace webrtc
diff --git a/modules/audio_processing/agc2/digital_gain_applier.h b/modules/audio_processing/agc2/digital_gain_applier.h
deleted file mode 100644
index 6e9be8e..0000000
--- a/modules/audio_processing/agc2/digital_gain_applier.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_AGC2_DIGITAL_GAIN_APPLIER_H_
-#define MODULES_AUDIO_PROCESSING_AGC2_DIGITAL_GAIN_APPLIER_H_
-
-#include "api/array_view.h"
-#include "modules/audio_processing/audio_buffer.h"
-
-namespace webrtc {
-
-class DigitalGainApplier {
- public:
-  DigitalGainApplier();
-
-  // Applies the specified gain to an array of samples.
-  void Process(float gain, rtc::ArrayView<float> samples);
-
- private:
-  void LimitToAllowedRange(rtc::ArrayView<float> x);
-};
-
-}  // namespace webrtc
-
-#endif  // MODULES_AUDIO_PROCESSING_AGC2_DIGITAL_GAIN_APPLIER_H_
diff --git a/modules/audio_processing/agc2/gain_controller2.cc b/modules/audio_processing/agc2/gain_controller2.cc
index 6c1ce45..4265500 100644
--- a/modules/audio_processing/agc2/gain_controller2.cc
+++ b/modules/audio_processing/agc2/gain_controller2.cc
@@ -10,55 +10,65 @@
 
 #include "modules/audio_processing/agc2/gain_controller2.h"
 
+#include <cmath>
+
 #include "modules/audio_processing/audio_buffer.h"
 #include "modules/audio_processing/logging/apm_data_dumper.h"
 #include "rtc_base/atomicops.h"
 #include "rtc_base/checks.h"
+#include "rtc_base/safe_minmax.h"
 
 namespace webrtc {
 
-namespace {
-
-constexpr float kGain = 0.5f;
-
-}  // namespace
-
 int GainController2::instance_count_ = 0;
 
-GainController2::GainController2(int sample_rate_hz)
-    : sample_rate_hz_(sample_rate_hz),
-      data_dumper_(new ApmDataDumper(
-        rtc::AtomicOps::Increment(&instance_count_))),
-      digital_gain_applier_(),
-      gain_(kGain) {
-  RTC_DCHECK(sample_rate_hz_ == AudioProcessing::kSampleRate8kHz ||
-             sample_rate_hz_ == AudioProcessing::kSampleRate16kHz ||
-             sample_rate_hz_ == AudioProcessing::kSampleRate32kHz ||
-             sample_rate_hz_ == AudioProcessing::kSampleRate48kHz);
-  data_dumper_->InitiateNewSetOfRecordings();
-  data_dumper_->DumpRaw("gain_", 1, &gain_);
-}
+GainController2::GainController2()
+    : data_dumper_(
+          new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+      sample_rate_hz_(AudioProcessing::kSampleRate48kHz),
+      fixed_gain_(1.f) {}
 
 GainController2::~GainController2() = default;
 
+void GainController2::Initialize(int sample_rate_hz) {
+  RTC_DCHECK(sample_rate_hz == AudioProcessing::kSampleRate8kHz ||
+             sample_rate_hz == AudioProcessing::kSampleRate16kHz ||
+             sample_rate_hz == AudioProcessing::kSampleRate32kHz ||
+             sample_rate_hz == AudioProcessing::kSampleRate48kHz);
+  sample_rate_hz_ = sample_rate_hz;
+  data_dumper_->InitiateNewSetOfRecordings();
+  data_dumper_->DumpRaw("sample_rate_hz", sample_rate_hz_);
+  data_dumper_->DumpRaw("fixed_gain_linear", fixed_gain_);
+}
+
 void GainController2::Process(AudioBuffer* audio) {
+  if (fixed_gain_ == 1.f)
+    return;
+
   for (size_t k = 0; k < audio->num_channels(); ++k) {
-    auto channel_view = rtc::ArrayView<float>(
-        audio->channels_f()[k], audio->num_frames());
-    digital_gain_applier_.Process(gain_, channel_view);
+    for (size_t j = 0; j < audio->num_frames(); ++j) {
+      audio->channels_f()[k][j] = rtc::SafeClamp(
+          fixed_gain_ * audio->channels_f()[k][j], -32768.f, 32767.f);
+    }
   }
 }
 
+void GainController2::ApplyConfig(
+    const AudioProcessing::Config::GainController2& config) {
+  RTC_DCHECK(Validate(config));
+  fixed_gain_ = std::pow(10.f, config.fixed_gain_db / 20.f);
+}
+
 bool GainController2::Validate(
     const AudioProcessing::Config::GainController2& config) {
-  return true;
+  return config.fixed_gain_db >= 0.f;
 }
 
 std::string GainController2::ToString(
     const AudioProcessing::Config::GainController2& config) {
   std::stringstream ss;
-  ss << "{"
-     << "enabled: " << (config.enabled ? "true" : "false") << "}";
+  ss << "{enabled: " << (config.enabled ? "true" : "false") << ", "
+     << "fixed_gain_dB: " << config.fixed_gain_db << "}";
   return ss.str();
 }
 
diff --git a/modules/audio_processing/agc2/gain_controller2.h b/modules/audio_processing/agc2/gain_controller2.h
index 9ab8656..1170687 100644
--- a/modules/audio_processing/agc2/gain_controller2.h
+++ b/modules/audio_processing/agc2/gain_controller2.h
@@ -14,7 +14,6 @@
 #include <memory>
 #include <string>
 
-#include "modules/audio_processing/agc2/digital_gain_applier.h"
 #include "modules/audio_processing/include/audio_processing.h"
 #include "rtc_base/constructormagic.h"
 
@@ -26,28 +25,26 @@
 // Gain Controller 2 aims to automatically adjust levels by acting on the
 // microphone gain and/or applying digital gain.
 //
-// It temporarily implements a hard-coded gain mode only.
+// Temporarily implements a fixed gain mode with hard-clipping.
 class GainController2 {
  public:
-  explicit GainController2(int sample_rate_hz);
+  GainController2();
   ~GainController2();
 
-  int sample_rate_hz() { return sample_rate_hz_; }
-
+  void Initialize(int sample_rate_hz);
   void Process(AudioBuffer* audio);
 
+  void ApplyConfig(const AudioProcessing::Config::GainController2& config);
   static bool Validate(const AudioProcessing::Config::GainController2& config);
   static std::string ToString(
       const AudioProcessing::Config::GainController2& config);
 
  private:
-  int sample_rate_hz_;
-  std::unique_ptr<ApmDataDumper> data_dumper_;
-  DigitalGainApplier digital_gain_applier_;
   static int instance_count_;
-  // TODO(alessiob): Remove once a meaningful gain controller mode is
-  // implemented.
-  const float gain_;
+  std::unique_ptr<ApmDataDumper> data_dumper_;
+  int sample_rate_hz_;
+  float fixed_gain_;
+
   RTC_DISALLOW_COPY_AND_ASSIGN(GainController2);
 };
 
diff --git a/modules/audio_processing/agc2/gain_controller2_unittest.cc b/modules/audio_processing/agc2/gain_controller2_unittest.cc
index 7c9acc6..46f654d 100644
--- a/modules/audio_processing/agc2/gain_controller2_unittest.cc
+++ b/modules/audio_processing/agc2/gain_controller2_unittest.cc
@@ -8,13 +8,12 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include <memory>
-#include <string>
+#include <algorithm>
 
 #include "api/array_view.h"
-#include "modules/audio_processing/agc2/digital_gain_applier.h"
 #include "modules/audio_processing/agc2/gain_controller2.h"
 #include "modules/audio_processing/audio_buffer.h"
+#include "rtc_base/checks.h"
 #include "test/gtest.h"
 
 namespace webrtc {
@@ -22,77 +21,76 @@
 
 namespace {
 
-constexpr size_t kNumFrames = 480u;
+constexpr size_t kFrameSizeMs = 10u;
 constexpr size_t kStereo = 2u;
 
 void SetAudioBufferSamples(float value, AudioBuffer* ab) {
+  // Sets all the samples in |ab| to |value|.
   for (size_t k = 0; k < ab->num_channels(); ++k) {
-    auto channel = rtc::ArrayView<float>(ab->channels_f()[k], ab->num_frames());
-    for (auto& sample : channel) { sample = value; }
+    std::fill(ab->channels_f()[k], ab->channels_f()[k] + ab->num_frames(),
+              value);
   }
 }
 
-template<typename Functor>
-bool CheckAudioBufferSamples(Functor validator, AudioBuffer* ab) {
-  for (size_t k = 0; k < ab->num_channels(); ++k) {
-    auto channel = rtc::ArrayView<float>(ab->channels_f()[k], ab->num_frames());
-    for (auto& sample : channel) { if (!validator(sample)) { return false; } }
-  }
-  return true;
-}
-
-bool TestDigitalGainApplier(float sample_value, float gain, float expected) {
-  AudioBuffer ab(kNumFrames, kStereo, kNumFrames, kStereo, kNumFrames);
-  SetAudioBufferSamples(sample_value, &ab);
-
-  DigitalGainApplier gain_applier;
-  for (size_t k = 0; k < ab.num_channels(); ++k) {
-    auto channel_view = rtc::ArrayView<float>(
-        ab.channels_f()[k], ab.num_frames());
-    gain_applier.Process(gain, channel_view);
-  }
-
-  auto check_expectation = [expected](float sample) {
-      return sample == expected; };
-  return CheckAudioBufferSamples(check_expectation, &ab);
-}
-
 }  // namespace
 
-TEST(GainController2, Instance) {
-  std::unique_ptr<GainController2> gain_controller2;
-  gain_controller2.reset(new GainController2(
-      AudioProcessing::kSampleRate48kHz));
+TEST(GainController2, CreateApplyConfig) {
+  // Instances GainController2 and applies different configurations.
+  std::unique_ptr<GainController2> gain_controller2(new GainController2());
+
+  // Check that the default config is valid.
+  AudioProcessing::Config::GainController2 config;
+  EXPECT_TRUE(GainController2::Validate(config));
+  gain_controller2->ApplyConfig(config);
+
+  // Check that attenuation is not allowed.
+  config.fixed_gain_db = -5.f;
+  EXPECT_FALSE(GainController2::Validate(config));
+
+  // Check that valid configurations are applied.
+  for (const float& fixed_gain_db : {0.f, 5.f, 10.f, 50.f}) {
+    config.fixed_gain_db = fixed_gain_db;
+    EXPECT_TRUE(GainController2::Validate(config));
+    gain_controller2->ApplyConfig(config);
+  }
 }
 
 TEST(GainController2, ToString) {
-  AudioProcessing::Config config;
+  // Tests GainController2::ToString().
+  AudioProcessing::Config::GainController2 config;
+  config.fixed_gain_db = 5.f;
 
-  config.gain_controller2.enabled = false;
-  EXPECT_EQ("{enabled: false}",
-            GainController2::ToString(config.gain_controller2));
+  config.enabled = false;
+  EXPECT_EQ("{enabled: false, fixed_gain_dB: 5}",
+            GainController2::ToString(config));
 
-  config.gain_controller2.enabled = true;
-  EXPECT_EQ("{enabled: true}",
-            GainController2::ToString(config.gain_controller2));
-}
-
-TEST(GainController2, DigitalGainApplierProcess) {
-  EXPECT_TRUE(TestDigitalGainApplier(1000.0f, 0.5, 500.0f));
-}
-
-TEST(GainController2, DigitalGainApplierCheckClipping) {
-  EXPECT_TRUE(TestDigitalGainApplier(30000.0f, 1.5, 32767.0f));
-  EXPECT_TRUE(TestDigitalGainApplier(-30000.0f, 1.5, -32767.0f));
+  config.enabled = true;
+  EXPECT_EQ("{enabled: true, fixed_gain_dB: 5}",
+            GainController2::ToString(config));
 }
 
 TEST(GainController2, Usage) {
-  std::unique_ptr<GainController2> gain_controller2;
-  gain_controller2.reset(new GainController2(
-      AudioProcessing::kSampleRate48kHz));
-  AudioBuffer ab(kNumFrames, kStereo, kNumFrames, kStereo, kNumFrames);
-  SetAudioBufferSamples(1000.0f, &ab);
+  // Tests GainController2::Process() on an AudioBuffer instance.
+  std::unique_ptr<GainController2> gain_controller2(new GainController2());
+  gain_controller2->Initialize(AudioProcessing::kSampleRate48kHz);
+  const size_t num_frames = rtc::CheckedDivExact<size_t>(
+      kFrameSizeMs * AudioProcessing::kSampleRate48kHz, 1000);
+  AudioBuffer ab(num_frames, kStereo, num_frames, kStereo, num_frames);
+  constexpr float sample_value = 1000.f;
+  SetAudioBufferSamples(sample_value, &ab);
+  AudioProcessing::Config::GainController2 config;
+
+  // Check that samples are not modified when the fixed gain is 0 dB.
+  ASSERT_EQ(config.fixed_gain_db, 0.f);
+  gain_controller2->ApplyConfig(config);
   gain_controller2->Process(&ab);
+  EXPECT_EQ(ab.channels_f()[0][0], sample_value);
+
+  // Check that samples are amplified when the fixed gain is greater than 0 dB.
+  config.fixed_gain_db = 5.f;
+  gain_controller2->ApplyConfig(config);
+  gain_controller2->Process(&ab);
+  EXPECT_LT(sample_value, ab.channels_f()[0][0]);
 }
 
 }  // namespace test
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 7aaad0a..c02fec2 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -253,7 +253,8 @@
 
 bool AudioProcessingImpl::ApmSubmoduleStates::CaptureFullBandProcessingActive()
     const {
-  return level_controller_enabled_ || capture_post_processor_enabled_;
+  return level_controller_enabled_ || gain_controller2_enabled_ ||
+         capture_post_processor_enabled_;
 }
 
 bool AudioProcessingImpl::ApmSubmoduleStates::RenderMultiBandSubModulesActive()
@@ -401,6 +402,10 @@
     // is enabled.
     private_submodules_->level_controller.reset(new LevelController());
 
+    // TODO(alessiob): Move the injected gain controller once injection is
+    // implemented.
+    private_submodules_->gain_controller2.reset(new GainController2());
+
     LOG(LS_INFO) << "Capture post processor activated: "
                  << !!private_submodules_->capture_post_processor;
   }
@@ -714,21 +719,16 @@
   config_ok = GainController2::Validate(config_.gain_controller2);
   if (!config_ok) {
     LOG(LS_ERROR) << "AudioProcessing module config error" << std::endl
-                  << "gain_controller2: "
+                  << "Gain Controller 2: "
                   << GainController2::ToString(config_.gain_controller2)
                   << std::endl
                   << "Reverting to default parameter set";
     config_.gain_controller2 = AudioProcessing::Config::GainController2();
   }
-
-  if (config.gain_controller2.enabled !=
-      capture_nonlocked_.gain_controller2_enabled) {
-    capture_nonlocked_.gain_controller2_enabled =
-        config_.gain_controller2.enabled;
-    InitializeGainController2();
-    LOG(LS_INFO) << "Gain controller 2 activated: "
-                 << capture_nonlocked_.gain_controller2_enabled;
-  }
+  InitializeGainController2();
+  private_submodules_->gain_controller2->ApplyConfig(config_.gain_controller2);
+  LOG(LS_INFO) << "Gain Controller 2 activated: "
+               << config_.gain_controller2.enabled;
 }
 
 void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) {
@@ -1305,7 +1305,7 @@
         capture_.key_pressed);
   }
 
-  if (capture_nonlocked_.gain_controller2_enabled) {
+  if (config_.gain_controller2.enabled) {
     private_submodules_->gain_controller2->Process(capture_buffer);
   }
 
@@ -1657,7 +1657,7 @@
       capture_nonlocked_.intelligibility_enabled,
       capture_nonlocked_.beamformer_enabled,
       public_submodules_->gain_control->is_enabled(),
-      capture_nonlocked_.gain_controller2_enabled,
+      config_.gain_controller2.enabled,
       capture_nonlocked_.level_controller_enabled,
       capture_nonlocked_.echo_canceller3_enabled,
       public_submodules_->voice_detection->is_enabled(),
@@ -1723,11 +1723,8 @@
 }
 
 void AudioProcessingImpl::InitializeGainController2() {
-  if (capture_nonlocked_.gain_controller2_enabled) {
-    private_submodules_->gain_controller2.reset(
-        new GainController2(proc_sample_rate_hz()));
-  } else {
-    private_submodules_->gain_controller2.reset();
+  if (config_.gain_controller2.enabled) {
+    private_submodules_->gain_controller2->Initialize(proc_sample_rate_hz());
   }
 }
 
@@ -1750,7 +1747,7 @@
   static const int kMinDiffDelayMs = 60;
 
   if (echo_cancellation()->is_enabled()) {
-    // Activate delay_jumps_ counters if we know echo_cancellation is runnning.
+    // Activate delay_jumps_ counters if we know echo_cancellation is running.
     // If a stream has echo we know that the echo_cancellation is in process.
     if (capture_.stream_delay_jumps == -1 &&
         echo_cancellation()->stream_has_echo()) {
@@ -1836,6 +1833,9 @@
   if (capture_nonlocked_.echo_canceller3_enabled) {
     experiments_description += "EchoCanceller3;";
   }
+  if (config_.gain_controller2.enabled) {
+    experiments_description += "GainController2;";
+  }
 
   InternalAPMConfig apm_config;
 
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index 6a58b41..2becc9e 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -374,7 +374,6 @@
     bool intelligibility_enabled;
     bool level_controller_enabled = false;
     bool echo_canceller3_enabled = false;
-    bool gain_controller2_enabled = false;
   } capture_nonlocked_;
 
   struct ApmRenderState {
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index e1828db..2610300 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -340,6 +340,7 @@
     // does not yet have the desired behavior.
     struct GainController2 {
       bool enabled = false;
+      float fixed_gain_db = 0.f;
     } gain_controller2;
 
     // Explicit copy assignment implementation to avoid issues with memory
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index 0926473..1683010 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -323,6 +323,7 @@
   }
   if (settings_.use_agc2) {
     apm_config.gain_controller2.enabled = *settings_.use_agc2;
+    apm_config.gain_controller2.fixed_gain_db = settings_.agc2_fixed_gain_db;
   }
   if (settings_.use_lc) {
     apm_config.level_controller.enabled = *settings_.use_lc;
diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h
index 9f81e6c..41a3f45 100644
--- a/modules/audio_processing/test/audio_processing_simulator.h
+++ b/modules/audio_processing/test/audio_processing_simulator.h
@@ -74,6 +74,7 @@
   rtc::Optional<int> agc_target_level;
   rtc::Optional<bool> use_agc_limiter;
   rtc::Optional<int> agc_compression_gain;
+  float agc2_fixed_gain_db;
   rtc::Optional<int> vad_likelihood;
   rtc::Optional<int> ns_level;
   rtc::Optional<bool> use_refined_adaptive_filter;
diff --git a/modules/audio_processing/test/audioproc_float.cc b/modules/audio_processing/test/audioproc_float.cc
index df7f43e..45ca8f0 100644
--- a/modules/audio_processing/test/audioproc_float.cc
+++ b/modules/audio_processing/test/audioproc_float.cc
@@ -149,6 +149,7 @@
 DEFINE_int(agc_compression_gain,
            kParameterNotSpecifiedValue,
            "Specify the AGC compression gain (0-90)");
+DEFINE_float(agc2_fixed_gain_db, 0.f, "AGC2 fixed gain (dB) to apply");
 DEFINE_int(vad_likelihood,
            kParameterNotSpecifiedValue,
            "Specify the VAD likelihood (0-3)");
@@ -214,6 +215,7 @@
     settings.use_ns = rtc::Optional<bool>(true);
     settings.use_hpf = rtc::Optional<bool>(true);
     settings.use_agc = rtc::Optional<bool>(true);
+    settings.use_agc2 = rtc::Optional<bool>(false);
     settings.use_aec = rtc::Optional<bool>(true);
     settings.use_aecm = rtc::Optional<bool>(false);
     settings.use_ed = rtc::Optional<bool>(false);
@@ -269,6 +271,7 @@
   SetSettingIfFlagSet(FLAG_agc_limiter, &settings.use_agc_limiter);
   SetSettingIfSpecified(FLAG_agc_compression_gain,
                         &settings.agc_compression_gain);
+  settings.agc2_fixed_gain_db = FLAG_agc2_fixed_gain_db;
   SetSettingIfSpecified(FLAG_vad_likelihood, &settings.vad_likelihood);
   SetSettingIfSpecified(FLAG_ns_level, &settings.ns_level);
   SetSettingIfSpecified(FLAG_stream_delay, &settings.stream_delay);
@@ -376,6 +379,17 @@
       "Error: --agc_compression_gain must be specified between 0 and 90.\n");
 
   ReportConditionalErrorAndExit(
+      settings.use_agc && *settings.use_agc && settings.use_agc2 &&
+          *settings.use_agc2,
+      "Error: --agc and --agc2 cannot be both active.\n");
+
+  ReportConditionalErrorAndExit(
+      settings.use_agc2 && *settings.use_agc2 &&
+          ((settings.agc2_fixed_gain_db) < 0 ||
+           (settings.agc2_fixed_gain_db) > 90),
+      "Error: --agc2_fixed_gain_db must be specified between 0 and 90.\n");
+
+  ReportConditionalErrorAndExit(
       settings.vad_likelihood &&
           ((*settings.vad_likelihood) < 0 || (*settings.vad_likelihood) > 3),
       "Error: --vad_likelihood must be specified between 0 and 3.\n");