Add replacement interface for webrtc::GainConrol

The pointer-to-submodule interfaces are being removed.
This CL:
1) introduces AudioProcessing::Config::GainController1 with most config,
2) adds functions to APM for setting and getting analog gain,
3) creates a temporary GainControlConfigProxy to support the transition
   to the new config.
4) Moves the lock references in GainControlForExperimentalAgc and
   GainControlImpl into the GainControlConfigProxy, as it becomes the
   sole AGC object with functionality exposed to the client.

Bug: webrtc:9947, webrtc:9878
Change-Id: Ic31e15e9bb26d6497a92b77874e0b6cab21ff2b2
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/126485
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Reviewed-by: Fredrik Solenberg <solenberg@webrtc.org>
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27316}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 504eb31..4d24ee6 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -28,6 +28,7 @@
 #include "modules/audio_processing/common.h"
 #include "modules/audio_processing/echo_cancellation_impl.h"
 #include "modules/audio_processing/echo_control_mobile_impl.h"
+#include "modules/audio_processing/gain_control_config_proxy.h"
 #include "modules/audio_processing/gain_control_for_experimental_agc.h"
 #include "modules/audio_processing/gain_control_impl.h"
 #include "modules/audio_processing/gain_controller2.h"
@@ -127,6 +128,19 @@
   }
 }
 
+GainControl::Mode Agc1ConfigModeToInterfaceMode(
+    AudioProcessing::Config::GainController1::Mode mode) {
+  using Agc1Config = AudioProcessing::Config::GainController1;
+  switch (mode) {
+    case Agc1Config::kAdaptiveAnalog:
+      return GainControl::kAdaptiveAnalog;
+    case Agc1Config::kAdaptiveDigital:
+      return GainControl::kAdaptiveDigital;
+    case Agc1Config::kFixedDigital:
+      return GainControl::kFixedDigital;
+  }
+}
+
 // Maximum lengths that frame of samples being passed from the render side to
 // the capture side can have (does not apply to AEC3).
 static const size_t kMaxAllowedValuesOfSamplesPerBand = 160;
@@ -254,13 +268,14 @@
   // Accessed externally of APM without any lock acquired.
   // TODO(bugs.webrtc.org/9947): Move these submodules into private_submodules_
   // when their pointer-to-submodule API functions are gone.
-  std::unique_ptr<GainControlImpl> gain_control;
   std::unique_ptr<LevelEstimatorImpl> level_estimator;
   std::unique_ptr<NoiseSuppressionImpl> noise_suppression;
   std::unique_ptr<NoiseSuppressionProxy> noise_suppression_proxy;
   std::unique_ptr<VoiceDetectionImpl> voice_detection;
+  std::unique_ptr<GainControlImpl> gain_control;
   std::unique_ptr<GainControlForExperimentalAgc>
       gain_control_for_experimental_agc;
+  std::unique_ptr<GainControlConfigProxy> gain_control_config_proxy;
 
   // Accessed internally from both render and capture.
   std::unique_ptr<TransientSuppressor> transient_suppressor;
@@ -393,7 +408,7 @@
   capture_nonlocked_.echo_controller_enabled =
       static_cast<bool>(echo_control_factory_);
 
-  public_submodules_->gain_control.reset(new GainControlImpl(&crit_capture_));
+  public_submodules_->gain_control.reset(new GainControlImpl());
   public_submodules_->level_estimator.reset(
       new LevelEstimatorImpl(&crit_capture_));
   public_submodules_->noise_suppression.reset(
@@ -403,8 +418,10 @@
   public_submodules_->voice_detection.reset(
       new VoiceDetectionImpl(&crit_capture_));
   public_submodules_->gain_control_for_experimental_agc.reset(
-      new GainControlForExperimentalAgc(public_submodules_->gain_control.get(),
-                                        &crit_capture_));
+      new GainControlForExperimentalAgc(
+          public_submodules_->gain_control.get()));
+  public_submodules_->gain_control_config_proxy.reset(
+      new GainControlConfigProxy(&crit_capture_, this, agc1()));
 
   // If no echo detector is injected, use the ResidualEchoDetector.
   if (!private_submodules_->echo_detector) {
@@ -680,6 +697,20 @@
        config_.echo_canceller.legacy_moderate_suppression_level !=
            config.echo_canceller.legacy_moderate_suppression_level);
 
+  const bool agc1_config_changed =
+      config_.gain_controller1.enabled != config.gain_controller1.enabled ||
+      config_.gain_controller1.mode != config.gain_controller1.mode ||
+      config_.gain_controller1.target_level_dbfs !=
+          config.gain_controller1.target_level_dbfs ||
+      config_.gain_controller1.compression_gain_db !=
+          config.gain_controller1.compression_gain_db ||
+      config_.gain_controller1.enable_limiter !=
+          config.gain_controller1.enable_limiter ||
+      config_.gain_controller1.analog_level_minimum !=
+          config.gain_controller1.analog_level_minimum ||
+      config_.gain_controller1.analog_level_maximum !=
+          config.gain_controller1.analog_level_maximum;
+
   config_ = config;
 
   if (aec_config_changed) {
@@ -696,6 +727,10 @@
   RTC_LOG(LS_INFO) << "Highpass filter activated: "
                    << config_.high_pass_filter.enabled;
 
+  if (agc1_config_changed) {
+    ApplyAgc1Config(config_.gain_controller1);
+  }
+
   const bool config_ok = GainController2::Validate(config_.gain_controller2);
   if (!config_ok) {
     RTC_LOG(LS_ERROR) << "AudioProcessing module config error\n"
@@ -730,6 +765,38 @@
   }
 }
 
+void AudioProcessingImpl::ApplyAgc1Config(
+    const Config::GainController1& config) {
+  GainControl* agc = agc1();
+  int error = agc->Enable(config.enabled);
+  RTC_DCHECK_EQ(kNoError, error);
+  error = agc->set_mode(Agc1ConfigModeToInterfaceMode(config.mode));
+  RTC_DCHECK_EQ(kNoError, error);
+  error = agc->set_target_level_dbfs(config.target_level_dbfs);
+  RTC_DCHECK_EQ(kNoError, error);
+  error = agc->set_compression_gain_db(config.compression_gain_db);
+  RTC_DCHECK_EQ(kNoError, error);
+  error = agc->enable_limiter(config.enable_limiter);
+  RTC_DCHECK_EQ(kNoError, error);
+  error = agc->set_analog_level_limits(config.analog_level_minimum,
+                                       config.analog_level_maximum);
+  RTC_DCHECK_EQ(kNoError, error);
+}
+
+GainControl* AudioProcessingImpl::agc1() {
+  if (constants_.use_experimental_agc) {
+    return public_submodules_->gain_control_for_experimental_agc.get();
+  }
+  return public_submodules_->gain_control.get();
+}
+
+const GainControl* AudioProcessingImpl::agc1() const {
+  if (constants_.use_experimental_agc) {
+    return public_submodules_->gain_control_for_experimental_agc.get();
+  }
+  return public_submodules_->gain_control.get();
+}
+
 void AudioProcessingImpl::SetExtraOptions(const webrtc::Config& config) {
   // Run in a single-threaded manner when setting the extra options.
   rtc::CritScope cs_render(&crit_render_);
@@ -793,6 +860,7 @@
       RTC_NOTREACHED();
       return;
     case RuntimeSetting::Type::kCapturePreGain:
+    case RuntimeSetting::Type::kCaptureCompressionGain:
       capture_runtime_settings_enqueuer_.Enqueue(setting);
       return;
   }
@@ -919,6 +987,15 @@
         }
         // TODO(bugs.chromium.org/9138): Log setting handling by Aec Dump.
         break;
+      case RuntimeSetting::Type::kCaptureCompressionGain: {
+        float value;
+        setting.GetFloat(&value);
+        int int_value = static_cast<int>(value + .5f);
+        config_.gain_controller1.compression_gain_db = int_value;
+        int error = agc1()->set_compression_gain_db(int_value);
+        RTC_DCHECK_EQ(kNoError, error);
+        break;
+      }
       case RuntimeSetting::Type::kCustomRenderProcessingRuntimeSetting:
         RTC_NOTREACHED();
         break;
@@ -941,9 +1018,8 @@
           private_submodules_->render_pre_processor->SetRuntimeSetting(setting);
         }
         break;
-      case RuntimeSetting::Type::kCapturePreGain:
-        RTC_NOTREACHED();
-        break;
+      case RuntimeSetting::Type::kCapturePreGain:          // fall-through
+      case RuntimeSetting::Type::kCaptureCompressionGain:  // fall-through
       case RuntimeSetting::Type::kNotSpecified:
         RTC_NOTREACHED();
         break;
@@ -1235,7 +1311,7 @@
 
   if (private_submodules_->echo_controller) {
     // Detect and flag any change in the analog gain.
-    int analog_mic_level = gain_control()->stream_analog_level();
+    int analog_mic_level = agc1()->stream_analog_level();
     capture_.echo_path_gain_change =
         capture_.prev_analog_mic_level != analog_mic_level &&
         capture_.prev_analog_mic_level != -1;
@@ -1389,7 +1465,7 @@
 
   if (config_.gain_controller2.enabled) {
     private_submodules_->gain_controller2->NotifyAnalogLevel(
-        gain_control()->stream_analog_level());
+        agc1()->stream_analog_level());
     private_submodules_->gain_controller2->Process(capture_buffer);
   }
 
@@ -1620,6 +1696,17 @@
   return capture_.delay_offset_ms;
 }
 
+void AudioProcessingImpl::set_stream_analog_level(int level) {
+  rtc::CritScope cs_capture(&crit_capture_);
+  int error = agc1()->set_stream_analog_level(level);
+  RTC_DCHECK_EQ(kNoError, error);
+}
+
+int AudioProcessingImpl::recommended_stream_analog_level() const {
+  rtc::CritScope cs_capture(&crit_capture_);
+  return agc1()->stream_analog_level();
+}
+
 void AudioProcessingImpl::AttachAecDump(std::unique_ptr<AecDump> aec_dump) {
   RTC_DCHECK(aec_dump);
   rtc::CritScope cs_render(&crit_render_);
@@ -1707,10 +1794,7 @@
 }
 
 GainControl* AudioProcessingImpl::gain_control() const {
-  if (constants_.use_experimental_agc) {
-    return public_submodules_->gain_control_for_experimental_agc.get();
-  }
-  return public_submodules_->gain_control.get();
+  return public_submodules_->gain_control_config_proxy.get();
 }
 
 LevelEstimator* AudioProcessingImpl::level_estimator() const {
@@ -2032,7 +2116,7 @@
   audio_proc_state.delay = capture_nonlocked_.stream_delay_ms;
   audio_proc_state.drift =
       private_submodules_->echo_cancellation->stream_drift_samples();
-  audio_proc_state.level = gain_control()->stream_analog_level();
+  audio_proc_state.level = agc1()->stream_analog_level();
   audio_proc_state.keypress = capture_.key_pressed;
   aec_dump_->AddAudioProcessingState(audio_proc_state);
 }