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_candidate_detection_threshold),
46 matched_filter_lag_aggregator_(data_dumper_,
47 matched_filter_.GetMaxFilterLag(),
48 config.delay.delay_selection_thresholds) {
49 RTC_DCHECK(data_dumper);
50 RTC_DCHECK(down_sampling_factor_ > 0);
51 }
52
53 EchoPathDelayEstimator::~EchoPathDelayEstimator() = default;
54
Reset(bool reset_delay_confidence)55 void EchoPathDelayEstimator::Reset(bool reset_delay_confidence) {
56 Reset(true, reset_delay_confidence);
57 }
58
EstimateDelay(const DownsampledRenderBuffer & render_buffer,const std::vector<std::vector<float>> & capture)59 absl::optional<DelayEstimate> EchoPathDelayEstimator::EstimateDelay(
60 const DownsampledRenderBuffer& render_buffer,
61 const std::vector<std::vector<float>>& capture) {
62 RTC_DCHECK_EQ(kBlockSize, capture[0].size());
63
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
76 absl::optional<DelayEstimate> aggregated_matched_filter_lag =
77 matched_filter_lag_aggregator_.Aggregate(
78 matched_filter_.GetLagEstimates());
79
80 // Run clockdrift detection.
81 if (aggregated_matched_filter_lag &&
82 (*aggregated_matched_filter_lag).quality ==
83 DelayEstimate::Quality::kRefined)
84 clockdrift_detector_.Update((*aggregated_matched_filter_lag).delay);
85
86 // TODO(peah): Move this logging outside of this class once EchoCanceller3
87 // development is done.
88 data_dumper_->DumpRaw(
89 "aec3_echo_path_delay_estimator_delay",
90 aggregated_matched_filter_lag
91 ? static_cast<int>(aggregated_matched_filter_lag->delay *
92 down_sampling_factor_)
93 : -1);
94
95 // Return the detected delay in samples as the aggregated matched filter lag
96 // compensated by the down sampling factor for the signal being correlated.
97 if (aggregated_matched_filter_lag) {
98 aggregated_matched_filter_lag->delay *= down_sampling_factor_;
99 }
100
101 if (old_aggregated_lag_ && aggregated_matched_filter_lag &&
102 old_aggregated_lag_->delay == aggregated_matched_filter_lag->delay) {
103 ++consistent_estimate_counter_;
104 } else {
105 consistent_estimate_counter_ = 0;
106 }
107 old_aggregated_lag_ = aggregated_matched_filter_lag;
108 constexpr size_t kNumBlocksPerSecondBy2 = kNumBlocksPerSecond / 2;
109 if (consistent_estimate_counter_ > kNumBlocksPerSecondBy2) {
110 Reset(false, false);
111 }
112
113 return aggregated_matched_filter_lag;
114 }
115
Reset(bool reset_lag_aggregator,bool reset_delay_confidence)116 void EchoPathDelayEstimator::Reset(bool reset_lag_aggregator,
117 bool reset_delay_confidence) {
118 if (reset_lag_aggregator) {
119 matched_filter_lag_aggregator_.Reset(reset_delay_confidence);
120 }
121 matched_filter_.Reset();
122 old_aggregated_lag_ = absl::nullopt;
123 consistent_estimate_counter_ = 0;
124 }
125 } // namespace webrtc
126