xref: /aosp_15_r20/external/webrtc/modules/audio_processing/aec3/echo_path_delay_estimator.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
11 
12 #include <array>
13 
14 #include "api/audio/echo_canceller3_config.h"
15 #include "modules/audio_processing/aec3/aec3_common.h"
16 #include "modules/audio_processing/aec3/downsampled_render_buffer.h"
17 #include "modules/audio_processing/logging/apm_data_dumper.h"
18 #include "rtc_base/checks.h"
19 
20 namespace webrtc {
21 
EchoPathDelayEstimator(ApmDataDumper * data_dumper,const EchoCanceller3Config & config,size_t num_capture_channels)22 EchoPathDelayEstimator::EchoPathDelayEstimator(
23     ApmDataDumper* data_dumper,
24     const EchoCanceller3Config& config,
25     size_t num_capture_channels)
26     : data_dumper_(data_dumper),
27       down_sampling_factor_(config.delay.down_sampling_factor),
28       sub_block_size_(down_sampling_factor_ != 0
29                           ? kBlockSize / down_sampling_factor_
30                           : kBlockSize),
31       capture_mixer_(num_capture_channels,
32                      config.delay.capture_alignment_mixing),
33       capture_decimator_(down_sampling_factor_),
34       matched_filter_(
35           data_dumper_,
36           DetectOptimization(),
37           sub_block_size_,
38           kMatchedFilterWindowSizeSubBlocks,
39           config.delay.num_filters,
40           kMatchedFilterAlignmentShiftSizeSubBlocks,
41           config.delay.down_sampling_factor == 8
42               ? config.render_levels.poor_excitation_render_limit_ds8
43               : config.render_levels.poor_excitation_render_limit,
44           config.delay.delay_estimate_smoothing,
45           config.delay.delay_estimate_smoothing_delay_found,
46           config.delay.delay_candidate_detection_threshold,
47           config.delay.detect_pre_echo),
48       matched_filter_lag_aggregator_(data_dumper_,
49                                      matched_filter_.GetMaxFilterLag(),
50                                      config.delay) {
51   RTC_DCHECK(data_dumper);
52   RTC_DCHECK(down_sampling_factor_ > 0);
53 }
54 
55 EchoPathDelayEstimator::~EchoPathDelayEstimator() = default;
56 
Reset(bool reset_delay_confidence)57 void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) {
58   Reset(true, reset_delay_confidence);
59 }
60 
EstimateDelay(const DownsampledRenderBuffer & render_buffer,const Block & capture)61 absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
62     const DownsampledRenderBuffer& render_buffer,
63     const Block& capture) {
64   std::array<float, kBlockSize> downsampled_capture_data;
65   rtc::ArrayView<float> downsampled_capture(downsampled_capture_data.data(),
66                                             sub_block_size_);
67 
68   std::array<float, kBlockSize> downmixed_capture;
69   capture_mixer_.ProduceOutput(capture, downmixed_capture);
70   capture_decimator_.Decimate(downmixed_capture, downsampled_capture);
71   data_dumper_->DumpWav("aec3_capture_decimator_output",
72                         downsampled_capture.size(), downsampled_capture.data(),
73                         16000 / down_sampling_factor_, 1);
74   matched_filter_.Update(render_buffer, downsampled_capture,
75                          matched_filter_lag_aggregator_.ReliableDelayFound());
76 
77   absl::optional<DelayEstimate> aggregated_matched_filter_lag =
78       matched_filter_lag_aggregator_.Aggregate(
79           matched_filter_.GetBestLagEstimate());
80 
81   // Run clockdrift detection.
82   if (aggregated_matched_filter_lag &&
83       (*aggregated_matched_filter_lag).quality ==
84           DelayEstimate::Quality::kRefined)
85     clockdrift_detector_.Update(
86         matched_filter_lag_aggregator_.GetDelayAtHighestPeak());
87 
88   // TODO(peah): Move this logging outside of this class once EchoCanceller3
89   // development is done.
90   data_dumper_->DumpRaw(
91       "aec3_echo_path_delay_estimator_delay",
92       aggregated_matched_filter_lag
93           ? static_cast<int>(aggregated_matched_filter_lag->delay *
94                              down_sampling_factor_)
95           : -1);
96 
97   // Return the detected delay in samples as the aggregated matched filter lag
98   // compensated by the down sampling factor for the signal being correlated.
99   if (aggregated_matched_filter_lag) {
100     aggregated_matched_filter_lag->delay *= down_sampling_factor_;
101   }
102 
103   if (old_aggregated_lag_ && aggregated_matched_filter_lag &&
104       old_aggregated_lag_->delay == aggregated_matched_filter_lag->delay) {
105     ++consistent_estimate_counter_;
106   } else {
107     consistent_estimate_counter_ = 0;
108   }
109   old_aggregated_lag_ = aggregated_matched_filter_lag;
110   constexpr size_t kNumBlocksPerSecondBy2 = kNumBlocksPerSecond / 2;
111   if (consistent_estimate_counter_ > kNumBlocksPerSecondBy2) {
112     Reset(false, false);
113   }
114 
115   return aggregated_matched_filter_lag;
116 }
117 
Reset(bool reset_lag_aggregator,bool reset_delay_confidence)118 void EchoPathDelayEstimator::Reset(bool reset_lag_aggregator,
119                                    bool reset_delay_confidence) {
120   if (reset_lag_aggregator) {
121     matched_filter_lag_aggregator_.Reset(reset_delay_confidence);
122   }
123   matched_filter_.Reset();
124   old_aggregated_lag_ = absl::nullopt;
125   consistent_estimate_counter_ = 0;
126 }
127 }  // namespace webrtc
128