OLD | NEW |
---|---|
(Empty) | |
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 | |
11 #include "webrtc/modules/audio_processing/aec3/aec_state.h" | |
12 | |
13 #include <math.h> | |
14 #include <numeric> | |
15 #include <vector> | |
16 | |
17 #include "webrtc/base/atomicops.h" | |
18 #include "webrtc/base/checks.h" | |
19 #include "webrtc/modules/audio_processing/logging/apm_data_dumper.h" | |
20 | |
21 namespace webrtc { | |
22 namespace { | |
23 | |
24 constexpr float kMaxFilterEstimateStrength = 1000.f; | |
25 | |
26 // Compute the delay of the adaptive filter as the partition with a distinct | |
27 // peak. | |
28 void AnalyzeFilter( | |
29 const std::vector<std::array<float, kFftLengthBy2Plus1>>& | |
30 filter_frequency_response, | |
31 std::array<bool, kFftLengthBy2Plus1>* bands_with_reliable_filter, | |
32 std::array<float, kFftLengthBy2Plus1>* filter_estimate_strength, | |
33 rtc::Optional<size_t>* filter_delay) { | |
34 const auto& H2 = filter_frequency_response; | |
35 | |
36 size_t reliable_delays_sum = 0; | |
37 size_t num_reliable_delays = 0; | |
38 | |
39 constexpr size_t kUpperBin = kFftLengthBy2 - 5; | |
40 for (size_t k = 1; k < kUpperBin; ++k) { | |
41 int peak = 0; | |
42 for (size_t j = 0; j < H2.size(); ++j) { | |
43 if (H2[j][k] > H2[peak][k]) { | |
44 peak = j; | |
45 } | |
46 } | |
47 | |
48 if (H2[peak][k] == 0.f) { | |
49 (*filter_estimate_strength)[k] = 0.f; | |
50 } else if (H2[H2.size() - 1][k] == 0.f) { | |
51 (*filter_estimate_strength)[k] = kMaxFilterEstimateStrength; | |
52 } else { | |
53 (*filter_estimate_strength)[k] = std::min( | |
54 kMaxFilterEstimateStrength, H2[peak][k] / H2[H2.size() - 1][k]); | |
55 } | |
56 | |
57 constexpr float kMargin = 10.f; | |
58 if (kMargin * H2[H2.size() - 1][k] < H2[peak][k]) { | |
59 (*bands_with_reliable_filter)[k] = true; | |
60 reliable_delays_sum += peak; | |
61 ++num_reliable_delays; | |
62 } else { | |
63 (*bands_with_reliable_filter)[k] = false; | |
64 } | |
65 } | |
66 (*bands_with_reliable_filter)[0] = (*bands_with_reliable_filter)[1]; | |
67 std::fill(bands_with_reliable_filter->begin() + kUpperBin, | |
68 bands_with_reliable_filter->end(), | |
69 (*bands_with_reliable_filter)[kUpperBin - 1]); | |
70 (*filter_estimate_strength)[0] = (*filter_estimate_strength)[1]; | |
71 std::fill(filter_estimate_strength->begin() + kUpperBin, | |
72 filter_estimate_strength->end(), | |
73 (*filter_estimate_strength)[kUpperBin - 1]); | |
74 | |
75 *filter_delay = | |
76 num_reliable_delays > 20 | |
77 ? rtc::Optional<size_t>(reliable_delays_sum / num_reliable_delays) | |
78 : rtc::Optional<size_t>(); | |
79 } | |
80 | |
81 constexpr int kActiveRenderCounterInitial = 50; | |
82 constexpr int kActiveRenderCounterMax = 200; | |
83 constexpr int kEchoPathChangeCounterInitial = 50; | |
84 constexpr int kEchoPathChangeCounterMax = 200; | |
85 | |
86 } // namespace | |
87 | |
88 int AecState::instance_count_ = 0; | |
89 | |
90 AecState::AecState() | |
91 : data_dumper_( | |
92 new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))), | |
93 echo_path_change_counter_(kEchoPathChangeCounterInitial), | |
94 active_render_counter_(kActiveRenderCounterInitial) { | |
95 bands_with_reliable_filter_.fill(false); | |
96 filter_estimate_strength_.fill(0.f); | |
97 } | |
98 | |
99 AecState::~AecState() = default; | |
100 | |
101 void AecState::Update(const std::vector<std::array<float, kFftLengthBy2Plus1>>& | |
102 filter_frequency_response, | |
103 const rtc::Optional<size_t>& external_delay_samples, | |
104 const FftBuffer& X_buffer, | |
105 const std::array<float, kFftLengthBy2Plus1>& E2_main, | |
106 const std::array<float, kFftLengthBy2Plus1>& E2_shadow, | |
107 const std::array<float, kFftLengthBy2Plus1>& Y2, | |
108 rtc::ArrayView<const float> x, | |
109 const EchoPathVariability& echo_path_variability, | |
110 bool echo_leakage_detected) { | |
111 filter_length_ = filter_frequency_response.size(); | |
112 AnalyzeFilter(filter_frequency_response, &bands_with_reliable_filter_, | |
113 &filter_estimate_strength_, &filter_delay_); | |
114 // Compute the externally provided delay in partitions. The truncation is | |
115 // intended here. | |
116 external_delay_ = | |
117 external_delay_samples | |
118 ? rtc::Optional<size_t>(*external_delay_samples / kBlockSize) | |
119 : rtc::Optional<size_t>(); | |
120 | |
121 const float x_energy = | |
122 std::accumulate(x.begin(), x.end(), 0.f, | |
hlundin-webrtc
2017/02/22 15:24:06
Optional: Could also use inner_product, I suppose.
peah-webrtc
2017/02/22 23:51:37
I changed to that as it makes the code more compac
| |
123 [](float a, float b) -> float { return a + b * b; }); | |
124 echo_path_change_counter_ = echo_path_variability.AudioPathChanged() | |
125 ? kEchoPathChangeCounterMax | |
126 : echo_path_change_counter_ - 1; | |
hlundin-webrtc
2017/02/22 15:24:06
What happens when echo_path_change_counter_ goes n
peah-webrtc
2017/02/22 23:51:37
Yes, that is intentional, as allowing it to go bel
hlundin-webrtc
2017/02/23 07:42:09
Acknowledged.
peah-webrtc
2017/02/23 11:18:32
Acknowledged.
| |
127 active_render_counter_ = x_energy > 10000 * kFftLengthBy2 | |
128 ? kActiveRenderCounterMax | |
129 : active_render_counter_ - 1; | |
hlundin-webrtc
2017/02/22 15:24:06
Same here.
peah-webrtc
2017/02/22 23:51:36
That is intended as well. The check is for when it
| |
130 | |
131 usable_linear_estimate_ = filter_delay_ && echo_path_change_counter_ <= 0; | |
132 | |
133 echo_leakage_detected_ = echo_leakage_detected; | |
134 | |
135 model_based_aec_feasible_ = usable_linear_estimate_ || external_delay_; | |
136 | |
137 if (usable_linear_estimate_) { | |
138 const std::array<float, kFftLengthBy2Plus1>& X2 = | |
hlundin-webrtc
2017/02/22 15:24:05
const auto&
peah-webrtc
2017/02/22 23:51:36
Done.
| |
139 X_buffer.Spectrum(*filter_delay_); | |
140 | |
141 // TODO(peah): Expose these as stats. | |
142 erle_estimator_.Update(X2, Y2, E2_main); | |
143 erl_estimator_.Update(X2, Y2); | |
144 | |
145 // TODO(peah): Add working functionality for headset detection. | |
146 const auto& erl = erl_estimator_.Erl(); | |
147 const int low_erl_band_count = std::count_if( | |
148 erl.begin(), erl.end(), [](float a) { return a <= 0.1f; }); | |
149 | |
150 const int noisy_band_count = std::count_if( | |
151 filter_estimate_strength_.begin(), filter_estimate_strength_.end(), | |
152 [](float a) { return a <= 10.f; }); | |
153 headset_detected_ = low_erl_band_count > 20 && noisy_band_count > 20; | |
154 headset_detected_ = false; | |
hlundin-webrtc
2017/02/22 15:24:06
Is this short-circuit because the above detection
peah-webrtc
2017/02/22 23:51:37
That is correct, or rather, it does not work yet.
hlundin-webrtc
2017/02/23 07:42:09
Acknowledged.
peah-webrtc
2017/02/23 11:18:32
Acknowledged.
| |
155 } else { | |
156 headset_detected_ = false; | |
157 } | |
158 } | |
159 | |
160 } // namespace webrtc | |
OLD | NEW |