diff --git a/modules/audio_processing/aec3/aec_state.h b/modules/audio_processing/aec3/aec_state.h index 9c8713302a..e9a46b4477 100644 --- a/modules/audio_processing/aec3/aec_state.h +++ b/modules/audio_processing/aec3/aec_state.h @@ -50,11 +50,17 @@ class AecState { return erle_estimator_.Erle(); } + // Returns the time-domain ERLE. + float ErleTimeDomain() const { return erle_estimator_.ErleTimeDomain(); } + // Returns the ERL. const std::array& Erl() const { return erl_estimator_.Erl(); } + // Returns the time-domain ERL. + float ErlTimeDomain() const { return erl_estimator_.ErlTimeDomain(); } + // Returns the delay estimate based on the linear filter. rtc::Optional FilterDelay() const { return filter_delay_; } diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc index 7de6dc2194..20c3669000 100644 --- a/modules/audio_processing/aec3/block_processor.cc +++ b/modules/audio_processing/aec3/block_processor.cc @@ -40,6 +40,8 @@ class BlockProcessorImpl final : public BlockProcessor { void UpdateEchoLeakageStatus(bool leakage_detected) override; + void GetMetrics(EchoControl::Metrics* metrics) const override; + private: static int instance_count_; bool no_capture_data_received_ = true; @@ -179,6 +181,10 @@ void BlockProcessorImpl::UpdateEchoLeakageStatus(bool leakage_detected) { echo_remover_->UpdateEchoLeakageStatus(leakage_detected); } +void BlockProcessorImpl::GetMetrics(EchoControl::Metrics* metrics) const { + echo_remover_->GetMetrics(metrics); +} + } // namespace BlockProcessor* BlockProcessor::Create(const EchoCanceller3Config& config, diff --git a/modules/audio_processing/aec3/block_processor.h b/modules/audio_processing/aec3/block_processor.h index 845e081350..8687bc2282 100644 --- a/modules/audio_processing/aec3/block_processor.h +++ b/modules/audio_processing/aec3/block_processor.h @@ -39,6 +39,9 @@ class BlockProcessor { virtual ~BlockProcessor() = default; + // Get current metrics. + virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0; + // Processes a block of capture data. virtual void ProcessCapture( bool echo_path_gain_change, diff --git a/modules/audio_processing/aec3/echo_canceller3.cc b/modules/audio_processing/aec3/echo_canceller3.cc index 93c98e4e22..491faa01fb 100644 --- a/modules/audio_processing/aec3/echo_canceller3.cc +++ b/modules/audio_processing/aec3/echo_canceller3.cc @@ -323,6 +323,13 @@ void EchoCanceller3::ProcessCapture(AudioBuffer* capture, bool level_change) { LowestBandRate(sample_rate_hz_), 1); } +EchoControl::Metrics EchoCanceller3::GetMetrics() const { + RTC_DCHECK_RUNS_SERIALIZED(&capture_race_checker_); + Metrics metrics; + block_processor_->GetMetrics(&metrics); + return metrics; +} + bool EchoCanceller3::Validate(const EchoCanceller3Config& config) { return true; } diff --git a/modules/audio_processing/aec3/echo_canceller3.h b/modules/audio_processing/aec3/echo_canceller3.h index f62016f9f6..475bacb723 100644 --- a/modules/audio_processing/aec3/echo_canceller3.h +++ b/modules/audio_processing/aec3/echo_canceller3.h @@ -79,6 +79,8 @@ class EchoCanceller3 : public EchoControl { // Processes the split-band domain capture signal in order to remove any echo // present in the signal. void ProcessCapture(AudioBuffer* capture, bool level_change) override; + // Collect current metrics from the echo canceller. + Metrics GetMetrics() const override; // Signals whether an external detector has detected echo leakage from the // echo canceller. diff --git a/modules/audio_processing/aec3/echo_canceller3_unittest.cc b/modules/audio_processing/aec3/echo_canceller3_unittest.cc index 66f5304dc1..75de48b547 100644 --- a/modules/audio_processing/aec3/echo_canceller3_unittest.cc +++ b/modules/audio_processing/aec3/echo_canceller3_unittest.cc @@ -102,6 +102,8 @@ class CaptureTransportVerificationProcessor : public BlockProcessor { void UpdateEchoLeakageStatus(bool leakage_detected) override {} + void GetMetrics(EchoControl::Metrics* metrics) const override {} + private: RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureTransportVerificationProcessor); }; @@ -128,6 +130,8 @@ class RenderTransportVerificationProcessor : public BlockProcessor { void UpdateEchoLeakageStatus(bool leakage_detected) override {} + void GetMetrics(EchoControl::Metrics* metrics) const override {} + private: std::deque>> received_render_blocks_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderTransportVerificationProcessor); diff --git a/modules/audio_processing/aec3/echo_remover.cc b/modules/audio_processing/aec3/echo_remover.cc index 72c629b7e8..9adcec51f4 100644 --- a/modules/audio_processing/aec3/echo_remover.cc +++ b/modules/audio_processing/aec3/echo_remover.cc @@ -53,6 +53,8 @@ class EchoRemoverImpl final : public EchoRemover { int sample_rate_hz); ~EchoRemoverImpl() override; + void GetMetrics(EchoControl::Metrics* metrics) const override; + // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. @@ -110,6 +112,13 @@ EchoRemoverImpl::EchoRemoverImpl(const EchoCanceller3Config& config, EchoRemoverImpl::~EchoRemoverImpl() = default; +void EchoRemoverImpl::GetMetrics(EchoControl::Metrics* metrics) const { + // Echo return loss (ERL) is inverted to go from gain to attenuation. + metrics->echo_return_loss = -10.0 * log10(aec_state_.ErlTimeDomain()); + metrics->echo_return_loss_enhancement = + 10.0 * log10(aec_state_.ErleTimeDomain()); +} + void EchoRemoverImpl::ProcessCapture( const rtc::Optional& echo_path_delay_samples, const EchoPathVariability& echo_path_variability, diff --git a/modules/audio_processing/aec3/echo_remover.h b/modules/audio_processing/aec3/echo_remover.h index ab56e388c7..7411b5c45c 100644 --- a/modules/audio_processing/aec3/echo_remover.h +++ b/modules/audio_processing/aec3/echo_remover.h @@ -27,6 +27,9 @@ class EchoRemover { int sample_rate_hz); virtual ~EchoRemover() = default; + // Get current metrics. + virtual void GetMetrics(EchoControl::Metrics* metrics) const = 0; + // Removes the echo from a block of samples from the capture signal. The // supplied render signal is assumed to be pre-aligned with the capture // signal. diff --git a/modules/audio_processing/aec3/erle_estimator.h b/modules/audio_processing/aec3/erle_estimator.h index 71fdfb50a5..d88b11bbb8 100644 --- a/modules/audio_processing/aec3/erle_estimator.h +++ b/modules/audio_processing/aec3/erle_estimator.h @@ -31,7 +31,7 @@ class ErleEstimator { // Returns the most recent ERLE estimate. const std::array& Erle() const { return erle_; } - float ErleTimeDomain() { return erle_time_domain_; } + float ErleTimeDomain() const { return erle_time_domain_; } private: std::array erle_; diff --git a/modules/audio_processing/aec3/mock/mock_block_processor.h b/modules/audio_processing/aec3/mock/mock_block_processor.h index 89adc8e522..5fff456185 100644 --- a/modules/audio_processing/aec3/mock/mock_block_processor.h +++ b/modules/audio_processing/aec3/mock/mock_block_processor.h @@ -30,6 +30,7 @@ class MockBlockProcessor : public BlockProcessor { MOCK_METHOD1(BufferRender, void(const std::vector>& block)); MOCK_METHOD1(UpdateEchoLeakageStatus, void(bool leakage_detected)); + MOCK_CONST_METHOD1(GetMetrics, void(EchoControl::Metrics* metrics)); }; } // namespace test diff --git a/modules/audio_processing/aec3/mock/mock_echo_remover.h b/modules/audio_processing/aec3/mock/mock_echo_remover.h index 06f6b8797d..44d3778e6d 100644 --- a/modules/audio_processing/aec3/mock/mock_echo_remover.h +++ b/modules/audio_processing/aec3/mock/mock_echo_remover.h @@ -34,6 +34,7 @@ class MockEchoRemover : public EchoRemover { std::vector>* capture)); MOCK_METHOD1(UpdateEchoLeakageStatus, void(bool leakage_detected)); + MOCK_CONST_METHOD1(GetMetrics, void(EchoControl::Metrics* metrics)); }; } // namespace test diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc index c8d0970502..8dac6029cc 100644 --- a/modules/audio_processing/audio_processing_impl.cc +++ b/modules/audio_processing/audio_processing_impl.cc @@ -1608,8 +1608,16 @@ AudioProcessing::AudioProcessingStats AudioProcessingImpl::GetStatistics( AudioProcessingStats stats; if (has_remote_tracks) { EchoCancellation::Metrics metrics; - if (public_submodules_->echo_cancellation->GetMetrics(&metrics) == - Error::kNoError) { + if (private_submodules_->echo_controller) { + rtc::CritScope cs_capture(&crit_capture_); + EchoControl::Metrics ec_metrics = + private_submodules_->echo_controller->GetMetrics(); + stats.echo_return_loss = + rtc::Optional(ec_metrics.echo_return_loss); + stats.echo_return_loss_enhancement = + rtc::Optional(ec_metrics.echo_return_loss_enhancement); + } else if (public_submodules_->echo_cancellation->GetMetrics(&metrics) == + Error::kNoError) { if (metrics.divergent_filter_fraction != -1.0f) { stats.divergent_filter_fraction = rtc::Optional(metrics.divergent_filter_fraction); diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h index 09fecabd6c..a4245c6b34 100644 --- a/modules/audio_processing/include/audio_processing.h +++ b/modules/audio_processing/include/audio_processing.h @@ -940,6 +940,14 @@ class EchoControl { // Processes the capture signal in order to remove the echo. virtual void ProcessCapture(AudioBuffer* capture, bool echo_path_change) = 0; + struct Metrics { + double echo_return_loss; + double echo_return_loss_enhancement; + }; + + // Collect current metrics from the echo controller. + virtual Metrics GetMetrics() const = 0; + virtual ~EchoControl() {} }; diff --git a/modules/audio_processing/include/mock_audio_processing.h b/modules/audio_processing/include/mock_audio_processing.h index d037e56b9b..7cbd166d01 100644 --- a/modules/audio_processing/include/mock_audio_processing.h +++ b/modules/audio_processing/include/mock_audio_processing.h @@ -119,6 +119,7 @@ class MockEchoControl : public EchoControl { MOCK_METHOD1(AnalyzeCapture, void(AudioBuffer* capture)); MOCK_METHOD2(ProcessCapture, void(AudioBuffer* capture, bool echo_path_change)); + MOCK_CONST_METHOD0(GetMetrics, Metrics()); }; class MockVoiceDetection : public VoiceDetection {