diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 027e1ed719..dd2ded6945 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -242,7 +242,6 @@ rtc_static_library("audio_processing") { "../../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 c1010669b0..7aaad0a20b 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -309,35 +309,33 @@ struct AudioProcessingImpl::ApmPrivateSubmodules { AudioProcessing* AudioProcessing::Create() { webrtc::Config config; - return Create(config, nullptr, rtc::Callback1(), nullptr); + return Create(config, nullptr, nullptr, nullptr); } AudioProcessing* AudioProcessing::Create(const webrtc::Config& config) { - return Create(config, nullptr, rtc::Callback1(), nullptr); + return Create(config, nullptr, nullptr, nullptr); } AudioProcessing* AudioProcessing::Create(const webrtc::Config& config, NonlinearBeamformer* beamformer) { - return Create(config, nullptr, rtc::Callback1(), - beamformer); + return Create(config, nullptr, nullptr, beamformer); } AudioProcessing* AudioProcessing::Create( const webrtc::Config& config, std::unique_ptr capture_post_processor, NonlinearBeamformer* beamformer) { - return Create(config, std::move(capture_post_processor), - rtc::Callback1(), beamformer); + return Create(config, std::move(capture_post_processor), nullptr, beamformer); } AudioProcessing* AudioProcessing::Create( const webrtc::Config& config, std::unique_ptr capture_post_processor, - rtc::Callback1 echo_control_factory, + std::unique_ptr echo_control_factory, NonlinearBeamformer* beamformer) { AudioProcessingImpl* apm = new rtc::RefCountedObject( - 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 @@ AudioProcessing* AudioProcessing::Create( } AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config) - : AudioProcessingImpl(config, - nullptr, - rtc::Callback1(), - nullptr) {} + : AudioProcessingImpl(config, nullptr, nullptr, nullptr) {} AudioProcessingImpl::AudioProcessingImpl( const webrtc::Config& config, std::unique_ptr capture_post_processor, - rtc::Callback1 echo_control_factory, + std::unique_ptr 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::InitializeLowCutFilter() { } 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 a5e16cbbf8..6a58b41fc5 100644 --- a/modules/audio_processing/audio_processing_impl.h +++ b/modules/audio_processing/audio_processing_impl.h @@ -43,7 +43,7 @@ class AudioProcessingImpl : public AudioProcessing { // beamformer. AudioProcessingImpl(const webrtc::Config& config, std::unique_ptr capture_post_processor, - rtc::Callback1 echo_control_factory, + std::unique_ptr echo_control_factory, NonlinearBeamformer* beamformer); ~AudioProcessingImpl() override; int Initialize() override; @@ -142,8 +142,8 @@ class AudioProcessingImpl : public AudioProcessing { // Submodule interface implementations. std::unique_ptr high_pass_filter_impl_; - // EchoControl factory method. - rtc::Callback1 echo_control_factory_; + // EchoControl factory. + std::unique_ptr 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 4540a6a3a3..c5df418af4 100644 --- a/modules/audio_processing/audio_processing_unittest.cc +++ b/modules/audio_processing/audio_processing_unittest.cc @@ -1316,8 +1316,8 @@ TEST_F(ApmTest, AgcOnlyAdaptsWhenTargetSignalIsPresent) { config.Set(new Beamforming(true, geometry)); testing::NiceMock* beamformer = new testing::NiceMock(geometry, 1u); - std::unique_ptr apm(AudioProcessing::Create( - config, nullptr, rtc::Callback1(), beamformer)); + std::unique_ptr apm( + AudioProcessing::Create(config, nullptr, nullptr, beamformer)); EXPECT_EQ(kNoErr, apm->gain_control()->Enable(true)); ChannelBuffer src_buf(kSamplesPerChannel, kNumInputChannels); ChannelBuffer dest_buf(kSamplesPerChannel, kNumOutputChannels); @@ -2915,9 +2915,8 @@ TEST(ApmConfiguration, EnablePostProcessing) { new testing::NiceMock(); auto mock_post_processor = std::unique_ptr(mock_post_processor_ptr); - rtc::scoped_refptr apm = - AudioProcessing::Create(webrtc_config, std::move(mock_post_processor), - rtc::Callback1(), nullptr); + rtc::scoped_refptr apm = AudioProcessing::Create( + webrtc_config, std::move(mock_post_processor), nullptr, nullptr); AudioFrame audio; audio.num_channels_ = 1; @@ -2927,4 +2926,31 @@ TEST(ApmConfiguration, EnablePostProcessing) { apm->ProcessStream(&audio); } +class MyEchoControlFactory : public EchoControlFactory { + public: + std::unique_ptr 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(ec); + } +}; + +TEST(ApmConfiguration, EchoControlInjection) { + // Verify that apm uses an injected echo controller if one is provided. + webrtc::Config webrtc_config; + std::unique_ptr echo_control_factory( + new MyEchoControlFactory()); + + rtc::scoped_refptr 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 2cbea501c6..e1828db794 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 ProcessingConfig; class EchoCancellation; class EchoControlMobile; -class EchoControl; +class EchoControlFactory; class GainControl; class HighPassFilter; class LevelEstimator; @@ -386,7 +385,7 @@ class AudioProcessing : public rtc::RefCountInterface { static AudioProcessing* Create( const webrtc::Config& config, std::unique_ptr capture_post_processor, - rtc::Callback1 echo_control_factory, + std::unique_ptr echo_control_factory, NonlinearBeamformer* beamformer); ~AudioProcessing() override {} @@ -971,6 +970,13 @@ class EchoControl { virtual ~EchoControl() {} }; +// Interface for a factory that creates EchoControllers. +class EchoControlFactory { + public: + virtual std::unique_ptr 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 c7a0f51204..d037e56b9b 100644 --- a/modules/audio_processing/include/mock_audio_processing.h +++ b/modules/audio_processing/include/mock_audio_processing.h @@ -112,6 +112,15 @@ class MockPostProcessing : public PostProcessing { 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() {}