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