Adding CustomAudioAnalyzer interface in APM.
CustomAudioAnalyzer is an interface of a component into APM that
reads AudioBuffer without changing it.
The APM sub-module is optional. It operates in full band.
As described in the comments, it is an experimental interface which
may be changed in the nearest future.
Change-Id: I21edf729d97947529256407b10fa4b5219bb2bf5
Bug: webrtc:9678
Reviewed-on: https://webrtc-review.googlesource.com/96560
Reviewed-by: Alessio Bazzica <alessiob@webrtc.org>
Commit-Queue: Alessio Bazzica <alessiob@webrtc.org>
Commit-Queue: Valeriia Nemychnikova <valeriian@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#24481}
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index 16053e6..4a1a86c 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -158,9 +158,11 @@
AudioProcessingImpl::ApmSubmoduleStates::ApmSubmoduleStates(
bool capture_post_processor_enabled,
- bool render_pre_processor_enabled)
+ bool render_pre_processor_enabled,
+ bool capture_analyzer_enabled)
: capture_post_processor_enabled_(capture_post_processor_enabled),
- render_pre_processor_enabled_(render_pre_processor_enabled) {}
+ render_pre_processor_enabled_(render_pre_processor_enabled),
+ capture_analyzer_enabled_(capture_analyzer_enabled) {}
bool AudioProcessingImpl::ApmSubmoduleStates::Update(
bool low_cut_filter_enabled,
@@ -240,6 +242,10 @@
pre_amplifier_enabled_;
}
+bool AudioProcessingImpl::ApmSubmoduleStates::CaptureAnalyzerActive() const {
+ return capture_analyzer_enabled_;
+}
+
bool AudioProcessingImpl::ApmSubmoduleStates::RenderMultiBandSubModulesActive()
const {
return RenderMultiBandProcessingActive() || echo_canceller_enabled_ ||
@@ -285,10 +291,12 @@
struct AudioProcessingImpl::ApmPrivateSubmodules {
ApmPrivateSubmodules(std::unique_ptr<CustomProcessing> capture_post_processor,
std::unique_ptr<CustomProcessing> render_pre_processor,
- rtc::scoped_refptr<EchoDetector> echo_detector)
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
: echo_detector(std::move(echo_detector)),
capture_post_processor(std::move(capture_post_processor)),
- render_pre_processor(std::move(render_pre_processor)) {}
+ render_pre_processor(std::move(render_pre_processor)),
+ capture_analyzer(std::move(capture_analyzer)) {}
// Accessed internally from capture or during initialization
std::unique_ptr<AgcManagerDirect> agc_manager;
std::unique_ptr<GainController2> gain_controller2;
@@ -298,6 +306,7 @@
std::unique_ptr<CustomProcessing> capture_post_processor;
std::unique_ptr<CustomProcessing> render_pre_processor;
std::unique_ptr<GainApplier> pre_amplifier;
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer;
};
AudioProcessingBuilder::AudioProcessingBuilder() = default;
@@ -315,6 +324,12 @@
return *this;
}
+AudioProcessingBuilder& AudioProcessingBuilder::SetCaptureAnalyzer(
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer) {
+ capture_analyzer_ = std::move(capture_analyzer);
+ return *this;
+}
+
AudioProcessingBuilder& AudioProcessingBuilder::SetEchoControlFactory(
std::unique_ptr<EchoControlFactory> echo_control_factory) {
echo_control_factory_ = std::move(echo_control_factory);
@@ -336,7 +351,7 @@
AudioProcessingImpl* apm = new rtc::RefCountedObject<AudioProcessingImpl>(
config, std::move(capture_post_processing_),
std::move(render_pre_processing_), std::move(echo_control_factory_),
- std::move(echo_detector_));
+ std::move(echo_detector_), std::move(capture_analyzer_));
if (apm->Initialize() != AudioProcessing::kNoError) {
delete apm;
apm = nullptr;
@@ -345,7 +360,8 @@
}
AudioProcessingImpl::AudioProcessingImpl(const webrtc::Config& config)
- : AudioProcessingImpl(config, nullptr, nullptr, nullptr, nullptr) {}
+ : AudioProcessingImpl(config, nullptr, nullptr, nullptr, nullptr, nullptr) {
+}
int AudioProcessingImpl::instance_count_ = 0;
@@ -354,7 +370,8 @@
std::unique_ptr<CustomProcessing> capture_post_processor,
std::unique_ptr<CustomProcessing> render_pre_processor,
std::unique_ptr<EchoControlFactory> echo_control_factory,
- rtc::scoped_refptr<EchoDetector> echo_detector)
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
: data_dumper_(
new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
capture_runtime_settings_(kRuntimeSettingQueueSize),
@@ -363,12 +380,15 @@
render_runtime_settings_enqueuer_(&render_runtime_settings_),
high_pass_filter_impl_(new HighPassFilterImpl(this)),
echo_control_factory_(std::move(echo_control_factory)),
- submodule_states_(!!capture_post_processor, !!render_pre_processor),
+ submodule_states_(!!capture_post_processor,
+ !!render_pre_processor,
+ !!capture_analyzer),
public_submodules_(new ApmPublicSubmodules()),
private_submodules_(
new ApmPrivateSubmodules(std::move(capture_post_processor),
std::move(render_pre_processor),
- std::move(echo_detector))),
+ std::move(echo_detector),
+ std::move(capture_analyzer))),
constants_(config.Get<ExperimentalAgc>().startup_min_volume,
config.Get<ExperimentalAgc>().clipped_level_min,
#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
@@ -425,7 +445,9 @@
// implemented.
private_submodules_->gain_controller2.reset(new GainController2());
- RTC_LOG(LS_INFO) << "Capture post processor activated: "
+ RTC_LOG(LS_INFO) << "Capture analyzer activated: "
+ << !!private_submodules_->capture_analyzer
+ << "\nCapture post processor activated: "
<< !!private_submodules_->capture_post_processor
<< "\nRender pre processor activated: "
<< !!private_submodules_->render_pre_processor;
@@ -578,6 +600,7 @@
InitializeResidualEchoDetector();
InitializeEchoController();
InitializeGainController2();
+ InitializeAnalyzer();
InitializePostProcessor();
InitializePreProcessor();
@@ -1350,6 +1373,11 @@
capture_.key_pressed);
}
+ // Experimental APM sub-module that analyzes |capture_buffer|.
+ if (private_submodules_->capture_analyzer) {
+ private_submodules_->capture_analyzer->Analyze(capture_buffer);
+ }
+
if (config_.gain_controller2.enabled) {
private_submodules_->gain_controller2->NotifyAnalogLevel(
gain_control()->stream_analog_level());
@@ -1854,6 +1882,13 @@
formats_.render_processing_format.sample_rate_hz(), 1);
}
+void AudioProcessingImpl::InitializeAnalyzer() {
+ if (private_submodules_->capture_analyzer) {
+ private_submodules_->capture_analyzer->Initialize(proc_sample_rate_hz(),
+ num_proc_channels());
+ }
+}
+
void AudioProcessingImpl::InitializePostProcessor() {
if (private_submodules_->capture_post_processor) {
private_submodules_->capture_post_processor->Initialize(
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index 44d0d08..06fa70c 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -42,7 +42,8 @@
std::unique_ptr<CustomProcessing> capture_post_processor,
std::unique_ptr<CustomProcessing> render_pre_processor,
std::unique_ptr<EchoControlFactory> echo_control_factory,
- rtc::scoped_refptr<EchoDetector> echo_detector);
+ rtc::scoped_refptr<EchoDetector> echo_detector,
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer);
~AudioProcessingImpl() override;
int Initialize() override;
int Initialize(int capture_input_sample_rate_hz,
@@ -174,7 +175,8 @@
class ApmSubmoduleStates {
public:
ApmSubmoduleStates(bool capture_post_processor_enabled,
- bool render_pre_processor_enabled);
+ bool render_pre_processor_enabled,
+ bool capture_analyzer_enabled);
// Updates the submodule state and returns true if it has changed.
bool Update(bool low_cut_filter_enabled,
bool echo_canceller_enabled,
@@ -192,6 +194,7 @@
bool CaptureMultiBandSubModulesActive() const;
bool CaptureMultiBandProcessingActive() const;
bool CaptureFullBandProcessingActive() const;
+ bool CaptureAnalyzerActive() const;
bool RenderMultiBandSubModulesActive() const;
bool RenderFullBandProcessingActive() const;
bool RenderMultiBandProcessingActive() const;
@@ -199,6 +202,7 @@
private:
const bool capture_post_processor_enabled_ = false;
const bool render_pre_processor_enabled_ = false;
+ const bool capture_analyzer_enabled_ = false;
bool low_cut_filter_enabled_ = false;
bool echo_canceller_enabled_ = false;
bool mobile_echo_controller_enabled_ = false;
@@ -252,6 +256,7 @@
void InitializeGainController2() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
void InitializePreAmplifier() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
void InitializePostProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
+ void InitializeAnalyzer() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_capture_);
void InitializePreProcessor() RTC_EXCLUSIVE_LOCKS_REQUIRED(crit_render_);
// Empties and handles the respective RuntimeSetting queues.
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 198c66d..b04f89a 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -2802,6 +2802,25 @@
apm->ProcessReverseStream(&audio);
}
+TEST(ApmConfiguration, EnableCaptureAnalyzer) {
+ // Verify that apm uses a capture analyzer if one is provided.
+ auto mock_capture_analyzer_ptr =
+ new testing::NiceMock<test::MockCustomAudioAnalyzer>();
+ auto mock_capture_analyzer =
+ std::unique_ptr<CustomAudioAnalyzer>(mock_capture_analyzer_ptr);
+ rtc::scoped_refptr<AudioProcessing> apm =
+ AudioProcessingBuilder()
+ .SetCaptureAnalyzer(std::move(mock_capture_analyzer))
+ .Create();
+
+ AudioFrame audio;
+ audio.num_channels_ = 1;
+ SetFrameSampleRate(&audio, AudioProcessing::NativeRate::kSampleRate16kHz);
+
+ EXPECT_CALL(*mock_capture_analyzer_ptr, Analyze(testing::_)).Times(1);
+ apm->ProcessStream(&audio);
+}
+
TEST(ApmConfiguration, PreProcessingReceivesRuntimeSettings) {
auto mock_pre_processor_ptr =
new testing::NiceMock<test::MockCustomProcessing>();
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index 22fa92d..e194be7 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -53,6 +53,7 @@
class HighPassFilter;
class LevelEstimator;
class NoiseSuppression;
+class CustomAudioAnalyzer;
class CustomProcessing;
class VoiceDetection;
@@ -675,6 +676,9 @@
// The AudioProcessingBuilder takes ownership of the echo_detector.
AudioProcessingBuilder& SetEchoDetector(
rtc::scoped_refptr<EchoDetector> echo_detector);
+ // The AudioProcessingBuilder takes ownership of the capture_analyzer.
+ AudioProcessingBuilder& SetCaptureAnalyzer(
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer);
// This creates an APM instance using the previously set components. Calling
// the Create function resets the AudioProcessingBuilder to its initial state.
AudioProcessing* Create();
@@ -685,6 +689,7 @@
std::unique_ptr<CustomProcessing> capture_post_processing_;
std::unique_ptr<CustomProcessing> render_pre_processing_;
rtc::scoped_refptr<EchoDetector> echo_detector_;
+ std::unique_ptr<CustomAudioAnalyzer> capture_analyzer_;
RTC_DISALLOW_COPY_AND_ASSIGN(AudioProcessingBuilder);
};
@@ -1018,6 +1023,19 @@
virtual ~NoiseSuppression() {}
};
+// Experimental interface for a custom analysis submodule.
+class CustomAudioAnalyzer {
+ public:
+ // (Re-) Initializes the submodule.
+ virtual void Initialize(int sample_rate_hz, int num_channels) = 0;
+ // Analyzes the given capture or render signal.
+ virtual void Analyze(const AudioBuffer* audio) = 0;
+ // Returns a string representation of the module state.
+ virtual std::string ToString() const = 0;
+
+ virtual ~CustomAudioAnalyzer() {}
+};
+
// Interface for a custom processing submodule.
class CustomProcessing {
public:
diff --git a/modules/audio_processing/include/mock_audio_processing.h b/modules/audio_processing/include/mock_audio_processing.h
index 9ceee10..2864e48 100644
--- a/modules/audio_processing/include/mock_audio_processing.h
+++ b/modules/audio_processing/include/mock_audio_processing.h
@@ -115,6 +115,14 @@
MOCK_CONST_METHOD0(ToString, std::string());
};
+class MockCustomAudioAnalyzer : public CustomAudioAnalyzer {
+ public:
+ virtual ~MockCustomAudioAnalyzer() {}
+ MOCK_METHOD2(Initialize, void(int sample_rate_hz, int num_channels));
+ MOCK_METHOD1(Analyze, void(const AudioBuffer* audio));
+ MOCK_CONST_METHOD0(ToString, std::string());
+};
+
class MockEchoControl : public EchoControl {
public:
virtual ~MockEchoControl() {}