Allow setting AEC3 config on the audio processing builder

Tested: Bitexact on a large set of aecdumps, except when aecdump settings are respected and AECM is used (then processing becomes more faithful to the stored aecdump settings). Also verified that --aec_settings still takes effect.
Bug: webrtc:442444736, b:428638881
Change-Id: If1a0671c8faf994ceeda5d9ec5d99218981c87d6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/411800
Reviewed-by: Jesus de Vicente Pena <devicentepena@webrtc.org>
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Commit-Queue: Sam Zackrisson <saza@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#45748}
diff --git a/api/audio/BUILD.gn b/api/audio/BUILD.gn
index 5e24cc7..2537979 100644
--- a/api/audio/BUILD.gn
+++ b/api/audio/BUILD.gn
@@ -106,6 +106,7 @@
     "builtin_audio_processing_builder.h",
   ]
   deps = [
+    ":aec3_config",
     ":audio_processing",
     ":echo_control",
     ":neural_residual_echo_estimator_api",
diff --git a/api/audio/builtin_audio_processing_builder.cc b/api/audio/builtin_audio_processing_builder.cc
index afb2e1a..b93187d 100644
--- a/api/audio/builtin_audio_processing_builder.cc
+++ b/api/audio/builtin_audio_processing_builder.cc
@@ -23,10 +23,10 @@
 absl_nullable scoped_refptr<AudioProcessing>
 BuiltinAudioProcessingBuilder::Build(const Environment& env) {
   return make_ref_counted<AudioProcessingImpl>(
-      env, config_, std::move(capture_post_processing_),
-      std::move(render_pre_processing_), std::move(echo_control_factory_),
-      std::move(echo_detector_), std::move(capture_analyzer_),
-      std::move(neural_residual_echo_estimator_));
+      env, config_, echo_canceller_config_, echo_canceller_multichannel_config_,
+      std::move(capture_post_processing_), std::move(render_pre_processing_),
+      std::move(echo_control_factory_), std::move(echo_detector_),
+      std::move(capture_analyzer_), std::move(neural_residual_echo_estimator_));
 }
 
 }  // namespace webrtc
diff --git a/api/audio/builtin_audio_processing_builder.h b/api/audio/builtin_audio_processing_builder.h
index bd8f495..396bfca 100644
--- a/api/audio/builtin_audio_processing_builder.h
+++ b/api/audio/builtin_audio_processing_builder.h
@@ -12,10 +12,12 @@
 #define API_AUDIO_BUILTIN_AUDIO_PROCESSING_BUILDER_H_
 
 #include <memory>
+#include <optional>
 #include <utility>
 
 #include "absl/base/nullability.h"
 #include "api/audio/audio_processing.h"
+#include "api/audio/echo_canceller3_config.h"
 #include "api/audio/echo_control.h"
 #include "api/audio/neural_residual_echo_estimator.h"
 #include "api/environment/environment.h"
@@ -42,6 +44,18 @@
     return *this;
   }
 
+  // Sets an echo canceller config to inject when APM is created. If a custom
+  // EchoControlFactory is also specified, this config has no effect.
+  // `echo_canceller_multichannel_config` is an optional config that, if
+  // specified, is applied for non-mono content.
+  BuiltinAudioProcessingBuilder& SetEchoCancellerConfig(
+      const EchoCanceller3Config& echo_canceller_config,
+      std::optional<EchoCanceller3Config> echo_canceller_multichannel_config) {
+    echo_canceller_config_ = echo_canceller_config;
+    echo_canceller_multichannel_config_ = echo_canceller_multichannel_config;
+    return *this;
+  }
+
   // Sets the echo controller factory to inject when APM is created.
   BuiltinAudioProcessingBuilder& SetEchoControlFactory(
       std::unique_ptr<EchoControlFactory> echo_control_factory) {
@@ -77,7 +91,7 @@
     return *this;
   }
 
-  // The AudioProcessingBuilder takes ownership of the
+  // The BuiltinAudioProcessingBuilder takes ownership of the
   // neural_residual_echo_estimator.
   BuiltinAudioProcessingBuilder& SetNeuralResidualEchoEstimator(
       std::unique_ptr<NeuralResidualEchoEstimator>
@@ -94,6 +108,8 @@
 
  private:
   AudioProcessing::Config config_;
+  std::optional<EchoCanceller3Config> echo_canceller_config_;
+  std::optional<EchoCanceller3Config> echo_canceller_multichannel_config_;
   std::unique_ptr<EchoControlFactory> echo_control_factory_;
   std::unique_ptr<CustomProcessing> capture_post_processing_;
   std::unique_ptr<CustomProcessing> render_pre_processing_;
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index b4e822b..0256ba0 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -433,6 +433,8 @@
 AudioProcessingImpl::AudioProcessingImpl(const Environment& env)
     : AudioProcessingImpl(env,
                           /*config=*/{},
+                          /*echo_canceller_config=*/std::nullopt,
+                          /*echo_canceller_multichannel_config=*/std::nullopt,
                           /*capture_post_processor=*/nullptr,
                           /*render_pre_processor=*/nullptr,
                           /*echo_control_factory=*/nullptr,
@@ -445,6 +447,8 @@
 AudioProcessingImpl::AudioProcessingImpl(
     const Environment& env,
     const AudioProcessing::Config& config,
+    std::optional<EchoCanceller3Config> echo_canceller_config,
+    std::optional<EchoCanceller3Config> echo_canceller_multichannel_config,
     std::unique_ptr<CustomProcessing> capture_post_processor,
     std::unique_ptr<CustomProcessing> render_pre_processor,
     std::unique_ptr<EchoControlFactory> echo_control_factory,
@@ -459,6 +463,8 @@
       render_runtime_settings_enqueuer_(&render_runtime_settings_),
       echo_control_factory_(std::move(echo_control_factory)),
       config_(config),
+      echo_canceller_config_(echo_canceller_config),
+      echo_canceller_multichannel_config_(echo_canceller_multichannel_config),
       submodule_states_(!!capture_post_processor,
                         !!render_pre_processor,
                         !!capture_analyzer),
@@ -1916,11 +1922,20 @@
           submodules_.neural_residual_echo_estimator.get());
       RTC_DCHECK(submodules_.echo_controller);
     } else {
-      EchoCanceller3Config config;
-      std::optional<EchoCanceller3Config> multichannel_config =
-          EchoCanceller3Config::CreateDefaultMultichannelConfig();
+      EchoCanceller3Config config_to_use =
+          echo_canceller_config_.value_or(EchoCanceller3Config());
+      std::optional<EchoCanceller3Config> multichannel_config_to_use =
+          echo_canceller_multichannel_config_;
+      if (!echo_canceller_config_.has_value() &&
+          !multichannel_config_to_use.has_value()) {
+        // We create a default multichannel config only if the user has set no
+        // config: If the user only provides a non-multichannel config, that
+        // config is used for both mono and multichannel AEC.
+        multichannel_config_to_use =
+            EchoCanceller3Config::CreateDefaultMultichannelConfig();
+      }
       submodules_.echo_controller = std::make_unique<EchoCanceller3>(
-          env_, config, multichannel_config,
+          env_, config_to_use, multichannel_config_to_use,
           submodules_.neural_residual_echo_estimator.get(),
           proc_sample_rate_hz(), num_reverse_channels(), num_proc_channels());
     }
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index 1dd958d..aab0005 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -25,6 +25,7 @@
 #include "api/array_view.h"
 #include "api/audio/audio_processing.h"
 #include "api/audio/audio_processing_statistics.h"
+#include "api/audio/echo_canceller3_config.h"
 #include "api/audio/echo_control.h"
 #include "api/audio/neural_residual_echo_estimator.h"
 #include "api/environment/environment.h"
@@ -63,15 +64,18 @@
   // Methods forcing APM to run in a single-threaded manner.
   // Acquires both the render and capture locks.
   explicit AudioProcessingImpl(const Environment& env);
-  AudioProcessingImpl(const Environment& env,
-                      const AudioProcessing::Config& config,
-                      std::unique_ptr<CustomProcessing> capture_post_processor,
-                      std::unique_ptr<CustomProcessing> render_pre_processor,
-                      std::unique_ptr<EchoControlFactory> echo_control_factory,
-                      scoped_refptr<EchoDetector> echo_detector,
-                      std::unique_ptr<CustomAudioAnalyzer> capture_analyzer,
-                      std::unique_ptr<NeuralResidualEchoEstimator>
-                          neural_residual_echo_estimator);
+  AudioProcessingImpl(
+      const Environment& env,
+      const AudioProcessing::Config& config,
+      std::optional<EchoCanceller3Config> echo_canceller_config,
+      std::optional<EchoCanceller3Config> echo_canceller_multichannel_config,
+      std::unique_ptr<CustomProcessing> capture_post_processor,
+      std::unique_ptr<CustomProcessing> render_pre_processor,
+      std::unique_ptr<EchoControlFactory> echo_control_factory,
+      scoped_refptr<EchoDetector> echo_detector,
+      std::unique_ptr<CustomAudioAnalyzer> capture_analyzer,
+      std::unique_ptr<NeuralResidualEchoEstimator>
+          neural_residual_echo_estimator);
   ~AudioProcessingImpl() override;
   int Initialize() override;
   int Initialize(const ProcessingConfig& processing_config) override;
@@ -361,6 +365,10 @@
   // Struct containing the Config specifying the behavior of APM.
   AudioProcessing::Config config_;
 
+  // AEC3 settings used when an EchoControlFactory is not present.
+  const std::optional<EchoCanceller3Config> echo_canceller_config_;
+  const std::optional<EchoCanceller3Config> echo_canceller_multichannel_config_;
+
   // Class containing information about what submodules are active.
   SubmoduleStates submodule_states_;
 
diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc
index ddf0647..5606cd8 100644
--- a/modules/audio_processing/test/audioproc_float_impl.cc
+++ b/modules/audio_processing/test/audioproc_float_impl.cc
@@ -28,7 +28,6 @@
 #include "api/audio/audio_processing.h"
 #include "api/audio/builtin_audio_processing_builder.h"
 #include "api/audio/echo_canceller3_config.h"
-#include "api/audio/echo_canceller3_factory.h"
 #include "api/audio/echo_detector_creator.h"
 #include "api/environment/environment.h"
 #include "api/environment/environment_factory.h"
@@ -789,30 +788,27 @@
 
 void SetDependencies(const SimulationSettings& settings,
                      BuiltinAudioProcessingBuilder& builder) {
-  // Create and set an EchoCanceller3Factory if needed.
-  if (settings.use_aec && *settings.use_aec) {
-    EchoCanceller3Config cfg;
-    if (settings.aec_settings_filename) {
-      if (settings.use_verbose_logging) {
-        std::cout << "Reading AEC Parameters from JSON input." << std::endl;
-      }
-      cfg = ReadAec3ConfigFromJsonFile(*settings.aec_settings_filename);
+  EchoCanceller3Config aec3_config;
+  if (settings.aec_settings_filename) {
+    if (settings.use_verbose_logging) {
+      std::cout << "Reading AEC Parameters from JSON input." << std::endl;
     }
-
-    if (settings.linear_aec_output_filename) {
-      cfg.filter.export_linear_aec_output = true;
-    }
-
-    if (settings.print_aec_parameter_values) {
-      if (!settings.use_quiet_output) {
-        std::cout << "AEC settings:" << std::endl;
-      }
-      std::cout << Aec3ConfigToJsonString(cfg) << std::endl;
-    }
-
-    builder.SetEchoControlFactory(std::make_unique<EchoCanceller3Factory>(cfg));
+    aec3_config = ReadAec3ConfigFromJsonFile(*settings.aec_settings_filename);
   }
 
+  if (settings.linear_aec_output_filename) {
+    aec3_config.filter.export_linear_aec_output = true;
+  }
+
+  if (settings.print_aec_parameter_values) {
+    if (!settings.use_quiet_output) {
+      std::cout << "AEC settings:" << std::endl;
+    }
+    std::cout << Aec3ConfigToJsonString(aec3_config) << std::endl;
+  }
+  builder.SetEchoCancellerConfig(
+      aec3_config, /*echo_canceller_multichannel_config=*/std::nullopt);
+
   if (settings.neural_echo_residual_estimator_model) {
     auto model_runner = NeuralResidualEchoEstimatorImpl::LoadTfLiteModel(
         *settings.neural_echo_residual_estimator_model);