blob: 71d149eb14b2d8280971439e9e9c86f071c2401f [file] [log] [blame]
peahe985b3f2017-02-28 22:08:53 -08001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/aec3/echo_remover_metrics.h"
peahe985b3f2017-02-28 22:08:53 -080012
13#include <math.h>
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <stddef.h>
peahe985b3f2017-02-28 22:08:53 -080015#include <algorithm>
Mirko Bonadeidbce0902019-03-15 07:39:02 +010016#include <cmath>
peahe985b3f2017-02-28 22:08:53 -080017#include <numeric>
18
Yves Gerey988cc082018-10-23 12:03:01 +020019#include "rtc_base/checks.h"
Karl Wiberge40468b2017-11-22 10:42:26 +010020#include "rtc_base/numerics/safe_minmax.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "system_wrappers/include/metrics.h"
peahe985b3f2017-02-28 22:08:53 -080022
23namespace webrtc {
24
25namespace {
26
27constexpr float kOneByMetricsCollectionBlocks = 1.f / kMetricsCollectionBlocks;
28
29} // namespace
30
31EchoRemoverMetrics::DbMetric::DbMetric() : DbMetric(0.f, 0.f, 0.f) {}
32EchoRemoverMetrics::DbMetric::DbMetric(float sum_value,
33 float floor_value,
34 float ceil_value)
35 : sum_value(sum_value), floor_value(floor_value), ceil_value(ceil_value) {}
36
37void EchoRemoverMetrics::DbMetric::Update(float value) {
38 sum_value += value;
39 floor_value = std::min(floor_value, value);
40 ceil_value = std::max(ceil_value, value);
41}
42
Gustaf Ullberg2723fb12017-11-23 14:46:48 +010043void EchoRemoverMetrics::DbMetric::UpdateInstant(float value) {
44 sum_value = value;
45 floor_value = std::min(floor_value, value);
46 ceil_value = std::max(ceil_value, value);
47}
48
peahe985b3f2017-02-28 22:08:53 -080049EchoRemoverMetrics::EchoRemoverMetrics() {
50 ResetMetrics();
51}
52
53void EchoRemoverMetrics::ResetMetrics() {
54 erl_.fill(DbMetric(0.f, 10000.f, 0.000f));
Gustaf Ullberg2723fb12017-11-23 14:46:48 +010055 erl_time_domain_ = DbMetric(0.f, 10000.f, 0.000f);
peahe985b3f2017-02-28 22:08:53 -080056 erle_.fill(DbMetric(0.f, 0.f, 1000.f));
Gustaf Ullberg2723fb12017-11-23 14:46:48 +010057 erle_time_domain_ = DbMetric(0.f, 0.f, 1000.f);
peahe985b3f2017-02-28 22:08:53 -080058 comfort_noise_.fill(DbMetric(0.f, 100000000.f, 0.f));
59 suppressor_gain_.fill(DbMetric(0.f, 1.f, 0.f));
60 active_render_count_ = 0;
61 saturated_capture_ = false;
62}
63
64void EchoRemoverMetrics::Update(
65 const AecState& aec_state,
66 const std::array<float, kFftLengthBy2Plus1>& comfort_noise_spectrum,
67 const std::array<float, kFftLengthBy2Plus1>& suppressor_gain) {
68 metrics_reported_ = false;
69 if (++block_counter_ <= kMetricsCollectionBlocks) {
70 aec3::UpdateDbMetric(aec_state.Erl(), &erl_);
Gustaf Ullberg2723fb12017-11-23 14:46:48 +010071 erl_time_domain_.UpdateInstant(aec_state.ErlTimeDomain());
peahe985b3f2017-02-28 22:08:53 -080072 aec3::UpdateDbMetric(aec_state.Erle(), &erle_);
Jesús de Vicente Peñae9a7e902018-09-27 11:49:39 +020073 erle_time_domain_.UpdateInstant(aec_state.FullBandErleLog2());
peahe985b3f2017-02-28 22:08:53 -080074 aec3::UpdateDbMetric(comfort_noise_spectrum, &comfort_noise_);
75 aec3::UpdateDbMetric(suppressor_gain, &suppressor_gain_);
76 active_render_count_ += (aec_state.ActiveRender() ? 1 : 0);
77 saturated_capture_ = saturated_capture_ || aec_state.SaturatedCapture();
78 } else {
79 // Report the metrics over several frames in order to lower the impact of
80 // the logarithms involved on the computational complexity.
81 constexpr int kMetricsCollectionBlocksBy2 = kMetricsCollectionBlocks / 2;
82 constexpr float kComfortNoiseScaling = 1.f / (kBlockSize * kBlockSize);
83 switch (block_counter_) {
84 case kMetricsCollectionBlocks + 1:
85 RTC_HISTOGRAM_COUNTS_LINEAR(
86 "WebRTC.Audio.EchoCanceller.ErleBand0.Average",
87 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f,
88 kOneByMetricsCollectionBlocks,
89 erle_[0].sum_value),
90 0, 19, 20);
91 RTC_HISTOGRAM_COUNTS_LINEAR(
92 "WebRTC.Audio.EchoCanceller.ErleBand0.Max",
93 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
94 erle_[0].ceil_value),
95 0, 19, 20);
96 RTC_HISTOGRAM_COUNTS_LINEAR(
97 "WebRTC.Audio.EchoCanceller.ErleBand0.Min",
98 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
99 erle_[0].floor_value),
100 0, 19, 20);
101 break;
102 case kMetricsCollectionBlocks + 2:
103 RTC_HISTOGRAM_COUNTS_LINEAR(
104 "WebRTC.Audio.EchoCanceller.ErleBand1.Average",
105 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f,
106 kOneByMetricsCollectionBlocks,
107 erle_[1].sum_value),
108 0, 19, 20);
109 RTC_HISTOGRAM_COUNTS_LINEAR(
110 "WebRTC.Audio.EchoCanceller.ErleBand1.Max",
111 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
112 erle_[1].ceil_value),
113 0, 19, 20);
114 RTC_HISTOGRAM_COUNTS_LINEAR(
115 "WebRTC.Audio.EchoCanceller.ErleBand1.Min",
116 aec3::TransformDbMetricForReporting(true, 0.f, 19.f, 0.f, 1.f,
117 erle_[1].floor_value),
118 0, 19, 20);
119 break;
120 case kMetricsCollectionBlocks + 3:
121 RTC_HISTOGRAM_COUNTS_LINEAR(
122 "WebRTC.Audio.EchoCanceller.ErlBand0.Average",
123 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f,
124 kOneByMetricsCollectionBlocks,
125 erl_[0].sum_value),
126 0, 59, 30);
127 RTC_HISTOGRAM_COUNTS_LINEAR(
128 "WebRTC.Audio.EchoCanceller.ErlBand0.Max",
129 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
130 erl_[0].ceil_value),
131 0, 59, 30);
132 RTC_HISTOGRAM_COUNTS_LINEAR(
133 "WebRTC.Audio.EchoCanceller.ErlBand0.Min",
134 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
135 erl_[0].floor_value),
136 0, 59, 30);
137 break;
138 case kMetricsCollectionBlocks + 4:
139 RTC_HISTOGRAM_COUNTS_LINEAR(
140 "WebRTC.Audio.EchoCanceller.ErlBand1.Average",
141 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f,
142 kOneByMetricsCollectionBlocks,
143 erl_[1].sum_value),
144 0, 59, 30);
145 RTC_HISTOGRAM_COUNTS_LINEAR(
146 "WebRTC.Audio.EchoCanceller.ErlBand1.Max",
147 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
148 erl_[1].ceil_value),
149 0, 59, 30);
150 RTC_HISTOGRAM_COUNTS_LINEAR(
151 "WebRTC.Audio.EchoCanceller.ErlBand1.Min",
152 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
153 erl_[1].floor_value),
154 0, 59, 30);
155 break;
156 case kMetricsCollectionBlocks + 5:
157 RTC_HISTOGRAM_COUNTS_LINEAR(
158 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand0.Average",
159 aec3::TransformDbMetricForReporting(
160 true, 0.f, 89.f, -90.3f,
161 kComfortNoiseScaling * kOneByMetricsCollectionBlocks,
162 comfort_noise_[0].sum_value),
163 0, 89, 45);
164 RTC_HISTOGRAM_COUNTS_LINEAR(
165 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand0.Max",
166 aec3::TransformDbMetricForReporting(true, 0.f, 89.f, -90.3f,
167 kComfortNoiseScaling,
168 comfort_noise_[0].ceil_value),
169 0, 89, 45);
170 RTC_HISTOGRAM_COUNTS_LINEAR(
171 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand0.Min",
172 aec3::TransformDbMetricForReporting(true, 0.f, 89.f, -90.3f,
173 kComfortNoiseScaling,
174 comfort_noise_[0].floor_value),
175 0, 89, 45);
176 break;
177 case kMetricsCollectionBlocks + 6:
178 RTC_HISTOGRAM_COUNTS_LINEAR(
179 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand1.Average",
180 aec3::TransformDbMetricForReporting(
181 true, 0.f, 89.f, -90.3f,
182 kComfortNoiseScaling * kOneByMetricsCollectionBlocks,
183 comfort_noise_[1].sum_value),
184 0, 89, 45);
185 RTC_HISTOGRAM_COUNTS_LINEAR(
186 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand1.Max",
187 aec3::TransformDbMetricForReporting(true, 0.f, 89.f, -90.3f,
188 kComfortNoiseScaling,
189 comfort_noise_[1].ceil_value),
190 0, 89, 45);
191 RTC_HISTOGRAM_COUNTS_LINEAR(
192 "WebRTC.Audio.EchoCanceller.ComfortNoiseBand1.Min",
193 aec3::TransformDbMetricForReporting(true, 0.f, 89.f, -90.3f,
194 kComfortNoiseScaling,
195 comfort_noise_[1].floor_value),
196 0, 89, 45);
197 break;
198 case kMetricsCollectionBlocks + 7:
199 RTC_HISTOGRAM_COUNTS_LINEAR(
200 "WebRTC.Audio.EchoCanceller.SuppressorGainBand0.Average",
201 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 0.f,
202 kOneByMetricsCollectionBlocks,
203 suppressor_gain_[0].sum_value),
204 0, 59, 30);
205 RTC_HISTOGRAM_COUNTS_LINEAR(
206 "WebRTC.Audio.EchoCanceller.SuppressorGainBand0.Max",
207 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 0.f, 1.f,
208 suppressor_gain_[0].ceil_value),
209 0, 59, 30);
210 RTC_HISTOGRAM_COUNTS_LINEAR(
211 "WebRTC.Audio.EchoCanceller.SuppressorGainBand0.Min",
212 aec3::TransformDbMetricForReporting(
213 true, 0.f, 59.f, 0.f, 1.f, suppressor_gain_[0].floor_value),
214 0, 59, 30);
215 break;
216 case kMetricsCollectionBlocks + 8:
217 RTC_HISTOGRAM_COUNTS_LINEAR(
218 "WebRTC.Audio.EchoCanceller.SuppressorGainBand1.Average",
219 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 0.f,
220 kOneByMetricsCollectionBlocks,
221 suppressor_gain_[1].sum_value),
222 0, 59, 30);
223 RTC_HISTOGRAM_COUNTS_LINEAR(
224 "WebRTC.Audio.EchoCanceller.SuppressorGainBand1.Max",
225 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 0.f, 1.f,
226 suppressor_gain_[1].ceil_value),
227 0, 59, 30);
228 RTC_HISTOGRAM_COUNTS_LINEAR(
229 "WebRTC.Audio.EchoCanceller.SuppressorGainBand1.Min",
230 aec3::TransformDbMetricForReporting(
231 true, 0.f, 59.f, 0.f, 1.f, suppressor_gain_[1].floor_value),
232 0, 59, 30);
233 break;
234 case kMetricsCollectionBlocks + 9:
235 RTC_HISTOGRAM_BOOLEAN(
236 "WebRTC.Audio.EchoCanceller.UsableLinearEstimate",
237 static_cast<int>(aec_state.UsableLinearEstimate() ? 1 : 0));
238 RTC_HISTOGRAM_BOOLEAN(
peahe985b3f2017-02-28 22:08:53 -0800239 "WebRTC.Audio.EchoCanceller.ActiveRender",
240 static_cast<int>(
241 active_render_count_ > kMetricsCollectionBlocksBy2 ? 1 : 0));
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100242 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.FilterDelay",
Per Åhgren5c532d32018-03-22 00:29:25 +0100243 aec_state.FilterDelayBlocks(), 0, 30, 31);
peahe985b3f2017-02-28 22:08:53 -0800244 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation",
245 static_cast<int>(saturated_capture_ ? 1 : 0));
Gustaf Ullberg2723fb12017-11-23 14:46:48 +0100246 break;
247 case kMetricsCollectionBlocks + 10:
248 RTC_HISTOGRAM_COUNTS_LINEAR(
249 "WebRTC.Audio.EchoCanceller.Erl.Value",
250 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
251 erl_time_domain_.sum_value),
252 0, 59, 30);
253 RTC_HISTOGRAM_COUNTS_LINEAR(
254 "WebRTC.Audio.EchoCanceller.Erl.Max",
255 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
256 erl_time_domain_.ceil_value),
257 0, 59, 30);
258 RTC_HISTOGRAM_COUNTS_LINEAR(
259 "WebRTC.Audio.EchoCanceller.Erl.Min",
260 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f,
261 erl_time_domain_.floor_value),
262 0, 59, 30);
263 break;
264 case kMetricsCollectionBlocks + 11:
265 RTC_HISTOGRAM_COUNTS_LINEAR(
266 "WebRTC.Audio.EchoCanceller.Erle.Value",
267 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
268 erle_time_domain_.sum_value),
269 0, 19, 20);
270 RTC_HISTOGRAM_COUNTS_LINEAR(
271 "WebRTC.Audio.EchoCanceller.Erle.Max",
272 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
273 erle_time_domain_.ceil_value),
274 0, 19, 20);
275 RTC_HISTOGRAM_COUNTS_LINEAR(
276 "WebRTC.Audio.EchoCanceller.Erle.Min",
277 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f,
278 erle_time_domain_.floor_value),
279 0, 19, 20);
peahe985b3f2017-02-28 22:08:53 -0800280 metrics_reported_ = true;
281 RTC_DCHECK_EQ(kMetricsReportingIntervalBlocks, block_counter_);
282 block_counter_ = 0;
283 ResetMetrics();
284 break;
285 default:
286 RTC_NOTREACHED();
287 break;
288 }
289 }
290}
291
292namespace aec3 {
293
294void UpdateDbMetric(const std::array<float, kFftLengthBy2Plus1>& value,
295 std::array<EchoRemoverMetrics::DbMetric, 2>* statistic) {
296 RTC_DCHECK(statistic);
297 // Truncation is intended in the band width computation.
298 constexpr int kNumBands = 2;
299 constexpr int kBandWidth = 65 / kNumBands;
300 constexpr float kOneByBandWidth = 1.f / kBandWidth;
301 RTC_DCHECK_EQ(kNumBands, statistic->size());
302 RTC_DCHECK_EQ(65, value.size());
303 for (size_t k = 0; k < statistic->size(); ++k) {
304 float average_band =
305 std::accumulate(value.begin() + kBandWidth * k,
306 value.begin() + kBandWidth * (k + 1), 0.f) *
307 kOneByBandWidth;
308 (*statistic)[k].Update(average_band);
309 }
310}
311
312int TransformDbMetricForReporting(bool negate,
313 float min_value,
314 float max_value,
315 float offset,
316 float scaling,
317 float value) {
Mirko Bonadeidbce0902019-03-15 07:39:02 +0100318 float new_value = 10.f * std::log10(value * scaling + 1e-10f) + offset;
peahe985b3f2017-02-28 22:08:53 -0800319 if (negate) {
320 new_value = -new_value;
321 }
kwiberg07038562017-06-12 11:40:47 -0700322 return static_cast<int>(rtc::SafeClamp(new_value, min_value, max_value));
peahe985b3f2017-02-28 22:08:53 -0800323}
324
325} // namespace aec3
326
327} // namespace webrtc