diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn index 181d797cc3..c7d36c6472 100644 --- a/modules/audio_processing/BUILD.gn +++ b/modules/audio_processing/BUILD.gn @@ -55,6 +55,7 @@ rtc_static_library("audio_processing") { "aec3/comfort_noise_generator.h", "aec3/decimator.cc", "aec3/decimator.h", + "aec3/delay_estimate.h", "aec3/downsampled_render_buffer.cc", "aec3/downsampled_render_buffer.h", "aec3/echo_canceller3.cc", diff --git a/modules/audio_processing/aec3/block_processor.cc b/modules/audio_processing/aec3/block_processor.cc index 4c83a55413..24f2c9176d 100644 --- a/modules/audio_processing/aec3/block_processor.cc +++ b/modules/audio_processing/aec3/block_processor.cc @@ -56,6 +56,7 @@ class BlockProcessorImpl final : public BlockProcessor { BlockProcessorMetrics metrics_; RenderDelayBuffer::BufferingEvent render_event_; size_t capture_call_counter_ = 0; + rtc::Optional estimated_delay_; RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorImpl); }; @@ -126,14 +127,17 @@ void BlockProcessorImpl::ProcessCapture( RTC_DCHECK(RenderDelayBuffer::BufferingEvent::kRenderOverrun != render_event_); if (render_event_ == RenderDelayBuffer::BufferingEvent::kRenderUnderrun) { - echo_path_variability.delay_change = - EchoPathVariability::DelayAdjustment::kDelayReset; - delay_controller_->Reset(); - capture_properly_started_ = false; - render_properly_started_ = false; + if (estimated_delay_ && + estimated_delay_->quality == DelayEstimate::Quality::kRefined) { + echo_path_variability.delay_change = + EchoPathVariability::DelayAdjustment::kDelayReset; + delay_controller_->Reset(); + capture_properly_started_ = false; + render_properly_started_ = false; - RTC_LOG(LS_WARNING) << "Reset due to render buffer underrrun at block " - << capture_call_counter_; + RTC_LOG(LS_WARNING) << "Reset due to render buffer underrrun at block " + << capture_call_counter_; + } } else if (render_event_ == RenderDelayBuffer::BufferingEvent::kApiCallSkew) { // There have been too many render calls in a row. Reset to avoid noncausal // echo. @@ -152,22 +156,23 @@ void BlockProcessorImpl::ProcessCapture( // Compute and and apply the render delay required to achieve proper signal // alignment. - rtc::Optional estimated_delay = delay_controller_->GetDelay( + estimated_delay_ = delay_controller_->GetDelay( render_buffer_->GetDownsampledRenderBuffer(), (*capture_block)[0]); - if (estimated_delay) { - bool delay_change = render_buffer_->SetDelay(*estimated_delay); - - if (delay_change) { - RTC_LOG(LS_WARNING) << "Delay changed to " << *estimated_delay - << " at block " << capture_call_counter_; - if (render_buffer_->CausalDelay()) { + if (estimated_delay_) { + if (render_buffer_->CausalDelay(estimated_delay_->delay)) { + bool delay_change = render_buffer_->SetDelay(estimated_delay_->delay); + if (delay_change) { + RTC_LOG(LS_WARNING) << "Delay changed to " << estimated_delay_->delay + << " at block " << capture_call_counter_; echo_path_variability.delay_change = EchoPathVariability::DelayAdjustment::kNewDetectedDelay; - } else { - // A noncausal delay has been detected. This can only happen if there is - // clockdrift, an audio pipeline issue has occurred or the specified - // minimum delay is too short. Perform a full reset. + } + } else { + // A noncausal delay has been detected. This can only happen if there is + // clockdrift, an audio pipeline issue has occurred, an unreliable delay + // estimate is used or the specified minimum delay is too short. + if (estimated_delay_->quality == DelayEstimate::Quality::kRefined) { echo_path_variability.delay_change = EchoPathVariability::DelayAdjustment::kDelayReset; delay_controller_->Reset(); diff --git a/modules/audio_processing/aec3/block_processor_unittest.cc b/modules/audio_processing/aec3/block_processor_unittest.cc index d23c1df41f..29b249b3b6 100644 --- a/modules/audio_processing/aec3/block_processor_unittest.cc +++ b/modules/audio_processing/aec3/block_processor_unittest.cc @@ -165,8 +165,7 @@ TEST(BlockProcessor, DISABLED_SubmoduleIntegration) { .Times(kNumBlocks) .WillRepeatedly(Return(0)); EXPECT_CALL(*render_delay_controller_mock, GetDelay(_, _)) - .Times(kNumBlocks) - .WillRepeatedly(Return(9)); + .Times(kNumBlocks); EXPECT_CALL(*echo_remover_mock, ProcessCapture(_, _, _, _)) .Times(kNumBlocks); EXPECT_CALL(*echo_remover_mock, UpdateEchoLeakageStatus(_)) diff --git a/modules/audio_processing/aec3/delay_estimate.h b/modules/audio_processing/aec3/delay_estimate.h new file mode 100644 index 0000000000..c3911f7f42 --- /dev/null +++ b/modules/audio_processing/aec3/delay_estimate.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ +#define MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ + +namespace webrtc { + +// Stores delay_estimates. +struct DelayEstimate { + enum class Quality { kCoarse, kRefined }; + + DelayEstimate(Quality quality, size_t delay) + : quality(quality), delay(delay) {} + + Quality quality; + size_t delay; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_AEC3_DELAY_ESTIMATE_H_ diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.cc b/modules/audio_processing/aec3/echo_path_delay_estimator.cc index 914f2d28eb..95796d52ea 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator.cc +++ b/modules/audio_processing/aec3/echo_path_delay_estimator.cc @@ -48,7 +48,7 @@ void EchoPathDelayEstimator::Reset() { matched_filter_.Reset(); } -rtc::Optional EchoPathDelayEstimator::EstimateDelay( +rtc::Optional EchoPathDelayEstimator::EstimateDelay( const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture) { RTC_DCHECK_EQ(kBlockSize, capture.size()); @@ -64,24 +64,25 @@ rtc::Optional EchoPathDelayEstimator::EstimateDelay( 16000 / down_sampling_factor_, 1); matched_filter_.Update(render_buffer, downsampled_capture); - rtc::Optional aggregated_matched_filter_lag = + rtc::Optional aggregated_matched_filter_lag = matched_filter_lag_aggregator_.Aggregate( matched_filter_.GetLagEstimates()); // TODO(peah): Move this logging outside of this class once EchoCanceller3 // development is done. - data_dumper_->DumpRaw("aec3_echo_path_delay_estimator_delay", - aggregated_matched_filter_lag - ? static_cast(*aggregated_matched_filter_lag * - down_sampling_factor_) - : -1); + data_dumper_->DumpRaw( + "aec3_echo_path_delay_estimator_delay", + aggregated_matched_filter_lag + ? static_cast(aggregated_matched_filter_lag->delay * + down_sampling_factor_) + : -1); // Return the detected delay in samples as the aggregated matched filter lag // compensated by the down sampling factor for the signal being correlated. - return aggregated_matched_filter_lag - ? rtc::Optional(*aggregated_matched_filter_lag * - down_sampling_factor_) - : rtc::nullopt; + if (aggregated_matched_filter_lag) { + aggregated_matched_filter_lag->delay *= down_sampling_factor_; + } + return aggregated_matched_filter_lag; } } // namespace webrtc diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator.h b/modules/audio_processing/aec3/echo_path_delay_estimator.h index 04943ca4ba..ef0d4483e1 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator.h +++ b/modules/audio_processing/aec3/echo_path_delay_estimator.h @@ -15,6 +15,7 @@ #include "api/optional.h" #include "modules/audio_processing/aec3/decimator.h" +#include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/matched_filter.h" #include "modules/audio_processing/aec3/matched_filter_lag_aggregator.h" @@ -36,7 +37,7 @@ class EchoPathDelayEstimator { void Reset(); // Produce a delay estimate if such is avaliable. - rtc::Optional EstimateDelay( + rtc::Optional EstimateDelay( const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture); diff --git a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc index 8d6488df1a..dbd7c0bbb5 100644 --- a/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc +++ b/modules/audio_processing/aec3/echo_path_delay_estimator_unittest.cc @@ -72,7 +72,7 @@ TEST(EchoPathDelayEstimator, DelayEstimation) { delay_samples + 2 * config.delay.api_call_jitter_blocks * 64); EchoPathDelayEstimator estimator(&data_dumper, config); - rtc::Optional estimated_delay_samples; + rtc::Optional estimated_delay_samples; for (size_t k = 0; k < (500 + (delay_samples) / kBlockSize); ++k) { RandomizeSampleVector(&random_generator, render[0]); signal_delay_buffer.Delay(render[0], capture); @@ -92,7 +92,7 @@ TEST(EchoPathDelayEstimator, DelayEstimation) { // Due to the internal down-sampling done inside the delay estimator // the estimated delay cannot be expected to be exact to the true delay. EXPECT_NEAR(delay_samples, - *estimated_delay_samples - + estimated_delay_samples->delay - (config.delay.api_call_jitter_blocks + 1) * 64, config.delay.down_sampling_factor); } else { diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc index 0a8d27cb5b..9041924b34 100644 --- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc +++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.cc @@ -30,7 +30,7 @@ void MatchedFilterLagAggregator::Reset() { significant_candidate_found_ = false; } -rtc::Optional MatchedFilterLagAggregator::Aggregate( +rtc::Optional MatchedFilterLagAggregator::Aggregate( rtc::ArrayView lag_estimates) { // Choose the strongest lag estimate as the best one. float best_accuracy = 0.f; @@ -69,9 +69,9 @@ rtc::Optional MatchedFilterLagAggregator::Aggregate( if (histogram_[candidate] > 25) { significant_candidate_found_ = true; - return candidate; + return DelayEstimate(DelayEstimate::Quality::kRefined, candidate); } else if (!significant_candidate_found_) { - return candidate; + return DelayEstimate(DelayEstimate::Quality::kCoarse, candidate); } } return rtc::nullopt; diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h index 4d72150d63..86968bd24f 100644 --- a/modules/audio_processing/aec3/matched_filter_lag_aggregator.h +++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator.h @@ -14,6 +14,7 @@ #include #include "api/optional.h" +#include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/matched_filter.h" #include "rtc_base/constructormagic.h" @@ -32,7 +33,7 @@ class MatchedFilterLagAggregator { void Reset(); // Aggregates the provided lag estimates. - rtc::Optional Aggregate( + rtc::Optional Aggregate( rtc::ArrayView lag_estimates); private: diff --git a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc index ce08f1cb05..ce303d4e38 100644 --- a/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc +++ b/modules/audio_processing/aec3/matched_filter_lag_aggregator_unittest.cc @@ -40,9 +40,10 @@ TEST(MatchedFilterLagAggregator, MostAccurateLagChosen) { EXPECT_TRUE(aggregator.Aggregate(lag_estimates)); } - rtc::Optional aggregated_lag = aggregator.Aggregate(lag_estimates); + rtc::Optional aggregated_lag = + aggregator.Aggregate(lag_estimates); EXPECT_TRUE(aggregated_lag); - EXPECT_EQ(kLag1, *aggregated_lag); + EXPECT_EQ(kLag1, aggregated_lag->delay); lag_estimates[0] = MatchedFilter::LagEstimate(0.5f, true, kLag1, true); lag_estimates[1] = MatchedFilter::LagEstimate(1.f, true, kLag2, true); @@ -50,13 +51,13 @@ TEST(MatchedFilterLagAggregator, MostAccurateLagChosen) { for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) { aggregated_lag = aggregator.Aggregate(lag_estimates); EXPECT_TRUE(aggregated_lag); - EXPECT_EQ(kLag1, *aggregated_lag); + EXPECT_EQ(kLag1, aggregated_lag->delay); } aggregated_lag = aggregator.Aggregate(lag_estimates); aggregated_lag = aggregator.Aggregate(lag_estimates); EXPECT_TRUE(aggregated_lag); - EXPECT_EQ(kLag2, *aggregated_lag); + EXPECT_EQ(kLag2, aggregated_lag->delay); } // Verifies that varying lag estimates causes lag estimates to not be deemed @@ -67,7 +68,7 @@ TEST(MatchedFilterLagAggregator, std::vector lag_estimates(1); MatchedFilterLagAggregator aggregator(&data_dumper, 100); - rtc::Optional aggregated_lag; + rtc::Optional aggregated_lag; for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) { lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, 10, true); aggregated_lag = aggregator.Aggregate(lag_estimates); @@ -97,9 +98,10 @@ TEST(MatchedFilterLagAggregator, MatchedFilterLagAggregator aggregator(&data_dumper, kLag); for (size_t k = 0; k < kNumLagsBeforeDetection * 10; ++k) { lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag, false); - rtc::Optional aggregated_lag = aggregator.Aggregate(lag_estimates); + rtc::Optional aggregated_lag = + aggregator.Aggregate(lag_estimates); EXPECT_FALSE(aggregated_lag); - EXPECT_EQ(kLag, *aggregated_lag); + EXPECT_EQ(kLag, aggregated_lag->delay); } } @@ -112,19 +114,19 @@ TEST(MatchedFilterLagAggregator, DISABLED_PersistentAggregatedLag) { ApmDataDumper data_dumper(0); std::vector lag_estimates(1); MatchedFilterLagAggregator aggregator(&data_dumper, std::max(kLag1, kLag2)); - rtc::Optional aggregated_lag; + rtc::Optional aggregated_lag; for (size_t k = 0; k < kNumLagsBeforeDetection; ++k) { lag_estimates[0] = MatchedFilter::LagEstimate(1.f, true, kLag1, true); aggregated_lag = aggregator.Aggregate(lag_estimates); } EXPECT_TRUE(aggregated_lag); - EXPECT_EQ(kLag1, *aggregated_lag); + EXPECT_EQ(kLag1, aggregated_lag->delay); for (size_t k = 0; k < kNumLagsBeforeDetection * 40; ++k) { lag_estimates[0] = MatchedFilter::LagEstimate(1.f, false, kLag2, true); aggregated_lag = aggregator.Aggregate(lag_estimates); EXPECT_TRUE(aggregated_lag); - EXPECT_EQ(kLag1, *aggregated_lag); + EXPECT_EQ(kLag1, aggregated_lag->delay); } } diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h index 2d3d9dcea2..1ed2b40e0c 100644 --- a/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h +++ b/modules/audio_processing/aec3/mock/mock_render_delay_buffer.h @@ -52,7 +52,7 @@ class MockRenderDelayBuffer : public RenderDelayBuffer { MOCK_METHOD0(GetRenderBuffer, RenderBuffer*()); MOCK_CONST_METHOD0(GetDownsampledRenderBuffer, const DownsampledRenderBuffer&()); - MOCK_CONST_METHOD0(CausalDelay, bool()); + MOCK_CONST_METHOD1(CausalDelay, bool(size_t delay)); private: RenderBuffer* FakeGetRenderBuffer() { return &render_buffer_; } diff --git a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h index 13dd8c28be..4a82ae3292 100644 --- a/modules/audio_processing/aec3/mock/mock_render_delay_controller.h +++ b/modules/audio_processing/aec3/mock/mock_render_delay_controller.h @@ -25,11 +25,10 @@ class MockRenderDelayController : public RenderDelayController { virtual ~MockRenderDelayController() = default; MOCK_METHOD0(Reset, void()); - MOCK_METHOD1(SetDelay, void(size_t render_delay)); MOCK_METHOD2( GetDelay, - rtc::Optional(const DownsampledRenderBuffer& render_buffer, - rtc::ArrayView capture)); + rtc::Optional(const DownsampledRenderBuffer& render_buffer, + rtc::ArrayView capture)); }; } // namespace test diff --git a/modules/audio_processing/aec3/render_delay_buffer.cc b/modules/audio_processing/aec3/render_delay_buffer.cc index 3181bae2cb..13737296df 100644 --- a/modules/audio_processing/aec3/render_delay_buffer.cc +++ b/modules/audio_processing/aec3/render_delay_buffer.cc @@ -47,7 +47,7 @@ class RenderDelayBufferImpl final : public RenderDelayBuffer { return low_rate_; } - bool CausalDelay() const override; + bool CausalDelay(size_t delay) const override; private: static int instance_count_; @@ -304,10 +304,14 @@ bool RenderDelayBufferImpl::SetDelay(size_t delay) { } // Returns whether the specified delay is causal. -bool RenderDelayBufferImpl::CausalDelay() const { - return !internal_delay_ || - *internal_delay_ >= - static_cast(config_.delay.min_echo_path_delay_blocks); +bool RenderDelayBufferImpl::CausalDelay(size_t delay) const { + // Compute the internal delay and limit the delay to the allowed range. + int internal_delay = MaxExternalDelayToInternalDelay(delay); + internal_delay = + std::min(MaxDelay(), static_cast(std::max(internal_delay, 0))); + + return internal_delay >= + static_cast(config_.delay.min_echo_path_delay_blocks); } // Maps the externally computed delay to the delay used internally. diff --git a/modules/audio_processing/aec3/render_delay_buffer.h b/modules/audio_processing/aec3/render_delay_buffer.h index b7718aa2c3..28ae32ba06 100644 --- a/modules/audio_processing/aec3/render_delay_buffer.h +++ b/modules/audio_processing/aec3/render_delay_buffer.h @@ -68,7 +68,7 @@ class RenderDelayBuffer { virtual const DownsampledRenderBuffer& GetDownsampledRenderBuffer() const = 0; // Returns whether the current delay is noncausal. - virtual bool CausalDelay() const = 0; + virtual bool CausalDelay(size_t delay) const = 0; // Returns the maximum non calusal offset that can occur in the delay buffer. static int DelayEstimatorOffset(const EchoCanceller3Config& config); diff --git a/modules/audio_processing/aec3/render_delay_controller.cc b/modules/audio_processing/aec3/render_delay_controller.cc index 799ea6b29b..3bc7d62237 100644 --- a/modules/audio_processing/aec3/render_delay_controller.cc +++ b/modules/audio_processing/aec3/render_delay_controller.cc @@ -32,9 +32,9 @@ class RenderDelayControllerImpl final : public RenderDelayController { int sample_rate_hz); ~RenderDelayControllerImpl() override; void Reset() override; - void SetDelay(size_t render_delay) override; - rtc::Optional GetDelay(const DownsampledRenderBuffer& render_buffer, - rtc::ArrayView capture) override; + rtc::Optional GetDelay( + const DownsampledRenderBuffer& render_buffer, + rtc::ArrayView capture) override; private: static int instance_count_; @@ -42,7 +42,7 @@ class RenderDelayControllerImpl final : public RenderDelayController { const int delay_headroom_blocks_; const int hysteresis_limit_1_blocks_; const int hysteresis_limit_2_blocks_; - rtc::Optional delay_; + rtc::Optional delay_; EchoPathDelayEstimator delay_estimator_; std::vector delay_buf_; int delay_buf_index_ = 0; @@ -50,34 +50,40 @@ class RenderDelayControllerImpl final : public RenderDelayController { RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RenderDelayControllerImpl); }; -size_t ComputeNewBufferDelay(const rtc::Optional& current_delay, - int delay_headroom_blocks, - int hysteresis_limit_1_blocks, - int hysteresis_limit_2_blocks, - size_t delay_samples) { +DelayEstimate ComputeNewBufferDelay( + const rtc::Optional& current_delay, + int delay_headroom_blocks, + int hysteresis_limit_1_blocks, + int hysteresis_limit_2_blocks, + DelayEstimate estimated_delay) { // The below division is not exact and the truncation is intended. - const int echo_path_delay_blocks = delay_samples >> kBlockSizeLog2; + const int echo_path_delay_blocks = estimated_delay.delay >> kBlockSizeLog2; // Compute the buffer delay increase required to achieve the desired latency. - size_t new_delay = + size_t new_delay_blocks = std::max(echo_path_delay_blocks - delay_headroom_blocks, 0); + DelayEstimate new_delay(estimated_delay.quality, new_delay_blocks); + // Add hysteresis. if (current_delay) { - if (new_delay > *current_delay) { - if (new_delay <= *current_delay + hysteresis_limit_1_blocks) { - new_delay = *current_delay; + size_t current_delay_blocks = current_delay->delay; + if (new_delay_blocks > current_delay_blocks) { + if (new_delay_blocks <= + current_delay_blocks + hysteresis_limit_1_blocks) { + new_delay_blocks = current_delay_blocks; } - } else if (new_delay < *current_delay) { + } else if (new_delay_blocks < current_delay_blocks) { size_t hysteresis_limit = std::max( - static_cast(*current_delay) - hysteresis_limit_2_blocks, 0); - if (new_delay >= hysteresis_limit) { - new_delay = *current_delay; + static_cast(current_delay_blocks) - hysteresis_limit_2_blocks, + 0); + if (new_delay_blocks >= hysteresis_limit) { + new_delay_blocks = current_delay_blocks; } } } - return new_delay; + return DelayEstimate(estimated_delay.quality, new_delay_blocks); } int RenderDelayControllerImpl::instance_count_ = 0; @@ -109,16 +115,7 @@ void RenderDelayControllerImpl::Reset() { delay_estimator_.Reset(); } -void RenderDelayControllerImpl::SetDelay(size_t render_delay) { - if (delay_ != render_delay) { - // If a the delay set does not match the actual delay, reset the delay - // controller. - Reset(); - delay_ = render_delay; - } -} - -rtc::Optional RenderDelayControllerImpl::GetDelay( +rtc::Optional RenderDelayControllerImpl::GetDelay( const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture) { RTC_DCHECK_EQ(kBlockSize, capture.size()); @@ -136,19 +133,21 @@ rtc::Optional RenderDelayControllerImpl::GetDelay( if (delay_samples) { // Compute and set new render delay buffer delay. - delay_ = ComputeNewBufferDelay( - delay_, delay_headroom_blocks_, hysteresis_limit_1_blocks_, - hysteresis_limit_2_blocks_, static_cast(*delay_samples)); - metrics_.Update(static_cast(*delay_samples), delay_ ? *delay_ : 0); + delay_ = ComputeNewBufferDelay(delay_, delay_headroom_blocks_, + hysteresis_limit_1_blocks_, + hysteresis_limit_2_blocks_, *delay_samples); + + metrics_.Update(static_cast(delay_samples->delay), + delay_ ? delay_->delay : 0); } else { - metrics_.Update(rtc::nullopt, delay_ ? *delay_ : 0); + metrics_.Update(rtc::nullopt, delay_ ? delay_->delay : 0); } data_dumper_->DumpRaw("aec3_render_delay_controller_delay", - delay_samples ? *delay_samples : 0); + delay_samples ? delay_samples->delay : 0); data_dumper_->DumpRaw("aec3_render_delay_controller_buffer_delay", - delay_ ? *delay_ : 0); + delay_ ? delay_->delay : 0); return delay_; } diff --git a/modules/audio_processing/aec3/render_delay_controller.h b/modules/audio_processing/aec3/render_delay_controller.h index a90ccb024b..5b1fc35ee9 100644 --- a/modules/audio_processing/aec3/render_delay_controller.h +++ b/modules/audio_processing/aec3/render_delay_controller.h @@ -13,6 +13,7 @@ #include "api/array_view.h" #include "api/optional.h" +#include "modules/audio_processing/aec3/delay_estimate.h" #include "modules/audio_processing/aec3/downsampled_render_buffer.h" #include "modules/audio_processing/aec3/render_delay_buffer.h" #include "modules/audio_processing/include/audio_processing.h" @@ -31,11 +32,8 @@ class RenderDelayController { // Resets the delay controller. virtual void Reset() = 0; - // Receives the externally used delay. - virtual void SetDelay(size_t render_delay) = 0; - // Aligns the render buffer content with the capture signal. - virtual rtc::Optional GetDelay( + virtual rtc::Optional GetDelay( const DownsampledRenderBuffer& render_buffer, rtc::ArrayView capture) = 0; }; diff --git a/modules/audio_processing/aec3/render_delay_controller_unittest.cc b/modules/audio_processing/aec3/render_delay_controller_unittest.cc index e91f7bd1a3..656c5e8817 100644 --- a/modules/audio_processing/aec3/render_delay_controller_unittest.cc +++ b/modules/audio_processing/aec3/render_delay_controller_unittest.cc @@ -61,9 +61,9 @@ TEST(RenderDelayController, NoRenderSignal) { RenderDelayController::Create( config, RenderDelayBuffer::DelayEstimatorOffset(config), rate)); for (size_t k = 0; k < 100; ++k) { - EXPECT_EQ(config.delay.min_echo_path_delay_blocks, - delay_controller->GetDelay( - delay_buffer->GetDownsampledRenderBuffer(), block)); + auto delay = delay_controller->GetDelay( + delay_buffer->GetDownsampledRenderBuffer(), block); + EXPECT_EQ(config.delay.min_echo_path_delay_blocks, delay->delay); } } } @@ -73,7 +73,7 @@ TEST(RenderDelayController, NoRenderSignal) { // Verifies the basic API call sequence. TEST(RenderDelayController, BasicApiCalls) { std::vector capture_block(kBlockSize, 0.f); - rtc::Optional delay_blocks = 0; + rtc::Optional delay_blocks; for (size_t num_matched_filters = 4; num_matched_filters == 10; num_matched_filters++) { for (auto down_sampling_factor : kDownSamplingFactors) { @@ -97,7 +97,7 @@ TEST(RenderDelayController, BasicApiCalls) { render_delay_buffer->GetDownsampledRenderBuffer(), capture_block); } EXPECT_TRUE(delay_blocks); - EXPECT_EQ(config.delay.min_echo_path_delay_blocks, delay_blocks); + EXPECT_EQ(config.delay.min_echo_path_delay_blocks, delay_blocks->delay); } } } @@ -120,7 +120,7 @@ TEST(RenderDelayController, Alignment) { NumBandsForRate(rate), std::vector(kBlockSize, 0.f)); for (size_t delay_samples : {15, 50, 150, 200, 800, 4000}) { - rtc::Optional delay_blocks; + rtc::Optional delay_blocks; SCOPED_TRACE(ProduceDebugText(rate, delay_samples)); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, NumBandsForRate(rate))); @@ -145,7 +145,7 @@ TEST(RenderDelayController, Alignment) { std::max(0, static_cast(delay_samples / kBlockSize) - kDelayHeadroomBlocks); - EXPECT_EQ(expected_delay_blocks, delay_blocks); + EXPECT_EQ(expected_delay_blocks, delay_blocks->delay); } } } @@ -169,7 +169,7 @@ TEST(RenderDelayController, NonCausalAlignment) { NumBandsForRate(rate), std::vector(kBlockSize, 0.f)); for (int delay_samples : {-15, -50, -150, -200}) { - rtc::Optional delay_blocks; + rtc::Optional delay_blocks; SCOPED_TRACE(ProduceDebugText(rate, -delay_samples)); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, NumBandsForRate(rate))); @@ -211,7 +211,7 @@ TEST(RenderDelayController, AlignmentWithJitter) { std::vector> render_block( NumBandsForRate(rate), std::vector(kBlockSize, 0.f)); for (size_t delay_samples : {15, 50, 300, 800}) { - rtc::Optional delay_blocks; + rtc::Optional delay_blocks; SCOPED_TRACE(ProduceDebugText(rate, delay_samples)); std::unique_ptr render_delay_buffer( RenderDelayBuffer::Create(config, NumBandsForRate(rate))); @@ -250,7 +250,7 @@ TEST(RenderDelayController, AlignmentWithJitter) { } ASSERT_TRUE(delay_blocks); - EXPECT_EQ(expected_delay_blocks, *delay_blocks); + EXPECT_EQ(expected_delay_blocks, delay_blocks->delay); } } }