• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/matched_filter_lag_aggregator.h"
11 
12 #include <algorithm>
13 #include <iterator>
14 
15 #include "modules/audio_processing/logging/apm_data_dumper.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/numerics/safe_minmax.h"
18 
19 namespace webrtc {
20 namespace {
21 constexpr int kPreEchoHistogramDataNotUpdated = -1;
22 
GetDownSamplingBlockSizeLog2(int down_sampling_factor)23 int GetDownSamplingBlockSizeLog2(int down_sampling_factor) {
24   int down_sampling_factor_log2 = 0;
25   down_sampling_factor >>= 1;
26   while (down_sampling_factor > 0) {
27     down_sampling_factor_log2++;
28     down_sampling_factor >>= 1;
29   }
30   return static_cast<int>(kBlockSizeLog2) > down_sampling_factor_log2
31              ? static_cast<int>(kBlockSizeLog2) - down_sampling_factor_log2
32              : 0;
33 }
34 }  // namespace
35 
MatchedFilterLagAggregator(ApmDataDumper * data_dumper,size_t max_filter_lag,const EchoCanceller3Config::Delay & delay_config)36 MatchedFilterLagAggregator::MatchedFilterLagAggregator(
37     ApmDataDumper* data_dumper,
38     size_t max_filter_lag,
39     const EchoCanceller3Config::Delay& delay_config)
40     : data_dumper_(data_dumper),
41       thresholds_(delay_config.delay_selection_thresholds),
42       headroom_(static_cast<int>(delay_config.delay_headroom_samples /
43                                  delay_config.down_sampling_factor)),
44       highest_peak_aggregator_(max_filter_lag) {
45   if (delay_config.detect_pre_echo) {
46     pre_echo_lag_aggregator_ = std::make_unique<PreEchoLagAggregator>(
47         max_filter_lag, delay_config.down_sampling_factor);
48   }
49   RTC_DCHECK(data_dumper);
50   RTC_DCHECK_LE(thresholds_.initial, thresholds_.converged);
51 }
52 
53 MatchedFilterLagAggregator::~MatchedFilterLagAggregator() = default;
54 
Reset(bool hard_reset)55 void MatchedFilterLagAggregator::Reset(bool hard_reset) {
56   highest_peak_aggregator_.Reset();
57   if (pre_echo_lag_aggregator_ != nullptr) {
58     pre_echo_lag_aggregator_->Reset();
59   }
60   if (hard_reset) {
61     significant_candidate_found_ = false;
62   }
63 }
64 
Aggregate(const absl::optional<const MatchedFilter::LagEstimate> & lag_estimate)65 absl::optional<DelayEstimate> MatchedFilterLagAggregator::Aggregate(
66     const absl::optional<const MatchedFilter::LagEstimate>& lag_estimate) {
67   if (lag_estimate && pre_echo_lag_aggregator_) {
68     pre_echo_lag_aggregator_->Dump(data_dumper_);
69     pre_echo_lag_aggregator_->Aggregate(
70         std::max(0, static_cast<int>(lag_estimate->pre_echo_lag) - headroom_));
71   }
72 
73   if (lag_estimate) {
74     highest_peak_aggregator_.Aggregate(
75         std::max(0, static_cast<int>(lag_estimate->lag) - headroom_));
76     rtc::ArrayView<const int> histogram = highest_peak_aggregator_.histogram();
77     int candidate = highest_peak_aggregator_.candidate();
78     significant_candidate_found_ = significant_candidate_found_ ||
79                                    histogram[candidate] > thresholds_.converged;
80     if (histogram[candidate] > thresholds_.converged ||
81         (histogram[candidate] > thresholds_.initial &&
82          !significant_candidate_found_)) {
83       DelayEstimate::Quality quality = significant_candidate_found_
84                                            ? DelayEstimate::Quality::kRefined
85                                            : DelayEstimate::Quality::kCoarse;
86       int reported_delay = pre_echo_lag_aggregator_ != nullptr
87                                ? pre_echo_lag_aggregator_->pre_echo_candidate()
88                                : candidate;
89       return DelayEstimate(quality, reported_delay);
90     }
91   }
92 
93   return absl::nullopt;
94 }
95 
HighestPeakAggregator(size_t max_filter_lag)96 MatchedFilterLagAggregator::HighestPeakAggregator::HighestPeakAggregator(
97     size_t max_filter_lag)
98     : histogram_(max_filter_lag + 1, 0) {
99   histogram_data_.fill(0);
100 }
101 
Reset()102 void MatchedFilterLagAggregator::HighestPeakAggregator::Reset() {
103   std::fill(histogram_.begin(), histogram_.end(), 0);
104   histogram_data_.fill(0);
105   histogram_data_index_ = 0;
106 }
107 
Aggregate(int lag)108 void MatchedFilterLagAggregator::HighestPeakAggregator::Aggregate(int lag) {
109   RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]);
110   RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]);
111   --histogram_[histogram_data_[histogram_data_index_]];
112   histogram_data_[histogram_data_index_] = lag;
113   RTC_DCHECK_GT(histogram_.size(), histogram_data_[histogram_data_index_]);
114   RTC_DCHECK_LE(0, histogram_data_[histogram_data_index_]);
115   ++histogram_[histogram_data_[histogram_data_index_]];
116   histogram_data_index_ = (histogram_data_index_ + 1) % histogram_data_.size();
117   candidate_ =
118       std::distance(histogram_.begin(),
119                     std::max_element(histogram_.begin(), histogram_.end()));
120 }
121 
PreEchoLagAggregator(size_t max_filter_lag,size_t down_sampling_factor)122 MatchedFilterLagAggregator::PreEchoLagAggregator::PreEchoLagAggregator(
123     size_t max_filter_lag,
124     size_t down_sampling_factor)
125     : block_size_log2_(GetDownSamplingBlockSizeLog2(down_sampling_factor)),
126       histogram_(
127           ((max_filter_lag + 1) * down_sampling_factor) >> kBlockSizeLog2,
128           0) {
129   Reset();
130 }
131 
Reset()132 void MatchedFilterLagAggregator::PreEchoLagAggregator::Reset() {
133   std::fill(histogram_.begin(), histogram_.end(), 0);
134   histogram_data_.fill(kPreEchoHistogramDataNotUpdated);
135   histogram_data_index_ = 0;
136   pre_echo_candidate_ = 0;
137 }
138 
Aggregate(int pre_echo_lag)139 void MatchedFilterLagAggregator::PreEchoLagAggregator::Aggregate(
140     int pre_echo_lag) {
141   int pre_echo_block_size = pre_echo_lag >> block_size_log2_;
142   RTC_DCHECK(pre_echo_block_size >= 0 &&
143              pre_echo_block_size < static_cast<int>(histogram_.size()));
144   pre_echo_block_size =
145       rtc::SafeClamp(pre_echo_block_size, 0, histogram_.size() - 1);
146   // Remove the oldest point from the `histogram_`, it ignores the initial
147   // points where no updates have been done to the `histogram_data_` array.
148   if (histogram_data_[histogram_data_index_] !=
149       kPreEchoHistogramDataNotUpdated) {
150     --histogram_[histogram_data_[histogram_data_index_]];
151   }
152   histogram_data_[histogram_data_index_] = pre_echo_block_size;
153   ++histogram_[histogram_data_[histogram_data_index_]];
154   histogram_data_index_ = (histogram_data_index_ + 1) % histogram_data_.size();
155   int pre_echo_candidate_block_size =
156       std::distance(histogram_.begin(),
157                     std::max_element(histogram_.begin(), histogram_.end()));
158   pre_echo_candidate_ = (pre_echo_candidate_block_size << block_size_log2_);
159 }
160 
Dump(ApmDataDumper * const data_dumper)161 void MatchedFilterLagAggregator::PreEchoLagAggregator::Dump(
162     ApmDataDumper* const data_dumper) {
163   data_dumper->DumpRaw("aec3_pre_echo_delay_candidate", pre_echo_candidate_);
164 }
165 
166 }  // namespace webrtc
167