Added EchoControlFactory interface.

The factory for EchoControl is changed from an rtc::Callback1 to an
interface. This avoids using rtc::Callback1 outside of WebRTC.
This also makes the EchoControl factory more similar to other
factories in the code base.

Bug: webrtc:8345
Change-Id: Ie61b9416ed771f8c756326736d17e339eb768469
Reviewed-on: https://webrtc-review.googlesource.com/8900
Reviewed-by: Per Ã…hgren <peah@webrtc.org>
Commit-Queue: Gustaf Ullberg <gustaf@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20272}
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index 027e1ed..dd2ded6 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -242,7 +242,6 @@
     "../../audio/utility:audio_frame_operations",
     "../../rtc_base:gtest_prod",
     "../../rtc_base:protobuf_utils",
-    "../../rtc_base:rtc_base",
     "../audio_coding:isac",
   ]
   public_deps = [
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index c101066..7aaad0a 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -309,35 +309,33 @@
 
 AudioProcessing* AudioProcessing::Create() {
   webrtc::Config config;
-  return Create(config, nullptr, rtc::Callback1<EchoControl*, int>(), nullptr);
+  return Create(config, nullptr, nullptr, nullptr);
 }
 
 AudioProcessing* AudioProcessing::Create(const webrtc::Config& config) {
-  return Create(config, nullptr, rtc::Callback1<EchoControl*, int>(), nullptr);
+  return Create(config, nullptr, nullptr, nullptr);
 }
 
 AudioProcessing* AudioProcessing::Create(const webrtc::Config& config,
                                          NonlinearBeamformer* beamformer) {
-  return Create(config, nullptr, rtc::Callback1<EchoControl*, int>(),
-                beamformer);
+  return Create(config, nullptr, nullptr, beamformer);
 }
 
 AudioProcessing* AudioProcessing::Create(
     const webrtc::Config& config,
     std::unique_ptr<PostProcessing> capture_post_processor,
     NonlinearBeamformer* beamformer) {
-  return Create(config, std::move(capture_post_processor),
-                rtc::Callback1<EchoControl*, int>(), beamformer);
+  return Create(config, std::move(capture_post_processor), nullptr, beamformer);
 }
 
 AudioProcessing* AudioProcessing::Create(
     const webrtc::Config& config,
     std::unique_ptr<PostProcessing> capture_post_processor,
-    rtc::Callback1<EchoControl*, int> echo_control_factory,
+    std::unique_ptr<EchoControlFactory> echo_control_factory,
     NonlinearBeamformer* beamformer) {
   AudioProcessingImpl* apm = new rtc::RefCountedObject<AudioProcessingImpl>(
-      config, std::move(capture_post_processor), echo_control_factory,
-      beamformer);
+      config, std::move(capture_post_processor),
+      std::move(echo_control_factory), beamformer);
   if (apm->Initialize() != kNoError) {
     delete apm;
     apm = nullptr;
@@ -347,18 +345,15 @@
 }
 
 AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config)
-    : AudioProcessingImpl(config,
-                          nullptr,
-                          rtc::Callback1<EchoControl*, int>(),
-                          nullptr) {}
+    : AudioProcessingImpl(config, nullptr, nullptr, nullptr) {}
 
 AudioProcessingImpl::AudioProcessingImpl(
     const webrtc::Config& config,
     std::unique_ptr<PostProcessing> capture_post_processor,
-    rtc::Callback1<EchoControl*, int> echo_control_factory,
+    std::unique_ptr<EchoControlFactory> echo_control_factory,
     NonlinearBeamformer* beamformer)
     : high_pass_filter_impl_(new HighPassFilterImpl(this)),
-      echo_control_factory_(echo_control_factory),
+      echo_control_factory_(std::move(echo_control_factory)),
       submodule_states_(!!capture_post_processor),
       public_submodules_(new ApmPublicSubmodules()),
       private_submodules_(
@@ -1715,9 +1710,9 @@
 }
 
 void AudioProcessingImpl::InitializeEchoCanceller3() {
-  if (!echo_control_factory_.empty()) {
-    private_submodules_->echo_controller.reset(
-        echo_control_factory_(proc_sample_rate_hz()));
+  if (echo_control_factory_) {
+    private_submodules_->echo_controller =
+        echo_control_factory_->Create(proc_sample_rate_hz());
   } else if (capture_nonlocked_.echo_canceller3_enabled) {
     // TODO(gustaf): Remove once injection is used.
     private_submodules_->echo_controller.reset(new EchoCanceller3(
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index a5e16cb..6a58b41 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -43,7 +43,7 @@
   // beamformer.
   AudioProcessingImpl(const webrtc::Config& config,
                       std::unique_ptr<PostProcessing> capture_post_processor,
-                      rtc::Callback1<EchoControl*, int> echo_control_factory,
+                      std::unique_ptr<EchoControlFactory> echo_control_factory,
                       NonlinearBeamformer* beamformer);
   ~AudioProcessingImpl() override;
   int Initialize() override;
@@ -142,8 +142,8 @@
   // Submodule interface implementations.
   std::unique_ptr<HighPassFilter> high_pass_filter_impl_;
 
-  // EchoControl factory method.
-  rtc::Callback1<EchoControl*, int> echo_control_factory_;
+  // EchoControl factory.
+  std::unique_ptr<EchoControlFactory> echo_control_factory_;
 
   class ApmSubmoduleStates {
    public:
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 4540a6a..c5df418 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -1316,8 +1316,8 @@
   config.Set<Beamforming>(new Beamforming(true, geometry));
   testing::NiceMock<MockNonlinearBeamformer>* beamformer =
       new testing::NiceMock<MockNonlinearBeamformer>(geometry, 1u);
-  std::unique_ptr<AudioProcessing> apm(AudioProcessing::Create(
-      config, nullptr, rtc::Callback1<EchoControl*, int>(), beamformer));
+  std::unique_ptr<AudioProcessing> apm(
+      AudioProcessing::Create(config, nullptr, nullptr, beamformer));
   EXPECT_EQ(kNoErr, apm->gain_control()->Enable(true));
   ChannelBuffer<float> src_buf(kSamplesPerChannel, kNumInputChannels);
   ChannelBuffer<float> dest_buf(kSamplesPerChannel, kNumOutputChannels);
@@ -2915,9 +2915,8 @@
       new testing::NiceMock<test::MockPostProcessing>();
   auto mock_post_processor =
       std::unique_ptr<PostProcessing>(mock_post_processor_ptr);
-  rtc::scoped_refptr<AudioProcessing> apm =
-      AudioProcessing::Create(webrtc_config, std::move(mock_post_processor),
-                              rtc::Callback1<EchoControl*, int>(), nullptr);
+  rtc::scoped_refptr<AudioProcessing> apm = AudioProcessing::Create(
+      webrtc_config, std::move(mock_post_processor), nullptr, nullptr);
 
   AudioFrame audio;
   audio.num_channels_ = 1;
@@ -2927,4 +2926,31 @@
   apm->ProcessStream(&audio);
 }
 
+class MyEchoControlFactory : public EchoControlFactory {
+ public:
+  std::unique_ptr<EchoControl> Create(int sample_rate_hz) {
+    auto ec = new test::MockEchoControl();
+    EXPECT_CALL(*ec, AnalyzeRender(testing::_)).Times(1);
+    EXPECT_CALL(*ec, AnalyzeCapture(testing::_)).Times(2);
+    EXPECT_CALL(*ec, ProcessCapture(testing::_, testing::_)).Times(2);
+    return std::unique_ptr<EchoControl>(ec);
+  }
+};
+
+TEST(ApmConfiguration, EchoControlInjection) {
+  // Verify that apm uses an injected echo controller if one is provided.
+  webrtc::Config webrtc_config;
+  std::unique_ptr<EchoControlFactory> echo_control_factory(
+      new MyEchoControlFactory());
+
+  rtc::scoped_refptr<AudioProcessing> apm = AudioProcessing::Create(
+      webrtc_config, nullptr, std::move(echo_control_factory), nullptr);
+
+  AudioFrame audio;
+  audio.num_channels_ = 1;
+  SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
+  apm->ProcessStream(&audio);
+  apm->ProcessReverseStream(&audio);
+  apm->ProcessStream(&audio);
+}
 }  // namespace webrtc
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 2cbea50..e1828db 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -23,7 +23,6 @@
 #include "modules/audio_processing/beamformer/array_util.h"
 #include "modules/audio_processing/include/config.h"
 #include "rtc_base/arraysize.h"
-#include "rtc_base/callback.h"
 #include "rtc_base/deprecation.h"
 #include "rtc_base/platform_file.h"
 #include "rtc_base/refcount.h"
@@ -44,7 +43,7 @@
 
 class EchoCancellation;
 class EchoControlMobile;
-class EchoControl;
+class EchoControlFactory;
 class GainControl;
 class HighPassFilter;
 class LevelEstimator;
@@ -386,7 +385,7 @@
   static AudioProcessing* Create(
       const webrtc::Config& config,
       std::unique_ptr<PostProcessing> capture_post_processor,
-      rtc::Callback1<EchoControl*, int> echo_control_factory,
+      std::unique_ptr<EchoControlFactory> echo_control_factory,
       NonlinearBeamformer* beamformer);
   ~AudioProcessing() override {}
 
@@ -971,6 +970,13 @@
   virtual ~EchoControl() {}
 };
 
+// Interface for a factory that creates EchoControllers.
+class EchoControlFactory {
+ public:
+  virtual std::unique_ptr<EchoControl> Create(int sample_rate_hz) = 0;
+  virtual ~EchoControlFactory() = default;
+};
+
 // The automatic gain control (AGC) component brings the signal to an
 // appropriate range. This is done by applying a digital gain directly and, in
 // the analog mode, prescribing an analog gain to be applied at the audio HAL.
diff --git a/modules/audio_processing/include/mock_audio_processing.h b/modules/audio_processing/include/mock_audio_processing.h
index c7a0f51..d037e56 100644
--- a/modules/audio_processing/include/mock_audio_processing.h
+++ b/modules/audio_processing/include/mock_audio_processing.h
@@ -112,6 +112,15 @@
   MOCK_CONST_METHOD0(ToString, std::string());
 };
 
+class MockEchoControl : public EchoControl {
+ public:
+  virtual ~MockEchoControl() {}
+  MOCK_METHOD1(AnalyzeRender, void(AudioBuffer* render));
+  MOCK_METHOD1(AnalyzeCapture, void(AudioBuffer* capture));
+  MOCK_METHOD2(ProcessCapture,
+               void(AudioBuffer* capture, bool echo_path_change));
+};
+
 class MockVoiceDetection : public VoiceDetection {
  public:
   virtual ~MockVoiceDetection() {}