echo_remover_metrics.cc (6222B)
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 "modules/audio_processing/aec3/echo_remover_metrics.h" 12 13 #include <algorithm> 14 #include <array> 15 #include <cmath> 16 #include <cstddef> 17 #include <numeric> 18 19 #include "modules/audio_processing/aec3/aec3_common.h" 20 #include "modules/audio_processing/aec3/aec_state.h" 21 #include "rtc_base/checks.h" 22 #include "rtc_base/numerics/safe_minmax.h" 23 #include "system_wrappers/include/metrics.h" 24 25 namespace webrtc { 26 27 EchoRemoverMetrics::DbMetric::DbMetric() : DbMetric(0.f, 0.f, 0.f) {} 28 EchoRemoverMetrics::DbMetric::DbMetric(float sum_value, 29 float floor_value, 30 float ceil_value) 31 : sum_value(sum_value), floor_value(floor_value), ceil_value(ceil_value) {} 32 33 void EchoRemoverMetrics::DbMetric::Update(float value) { 34 sum_value += value; 35 floor_value = std::min(floor_value, value); 36 ceil_value = std::max(ceil_value, value); 37 } 38 39 void EchoRemoverMetrics::DbMetric::UpdateInstant(float value) { 40 sum_value = value; 41 floor_value = std::min(floor_value, value); 42 ceil_value = std::max(ceil_value, value); 43 } 44 45 EchoRemoverMetrics::EchoRemoverMetrics() { 46 ResetMetrics(); 47 } 48 49 void EchoRemoverMetrics::ResetMetrics() { 50 erl_time_domain_ = DbMetric(0.f, 10000.f, 0.000f); 51 erle_time_domain_ = DbMetric(0.f, 0.f, 1000.f); 52 saturated_capture_ = false; 53 } 54 55 void EchoRemoverMetrics::Update( 56 const AecState& aec_state, 57 const std::array<float, kFftLengthBy2Plus1>& /* comfort_noise_spectrum */, 58 const std::array<float, kFftLengthBy2Plus1>& /* suppressor_gain */) { 59 metrics_reported_ = false; 60 if (++block_counter_ <= kMetricsCollectionBlocks) { 61 erl_time_domain_.UpdateInstant(aec_state.ErlTimeDomain()); 62 erle_time_domain_.UpdateInstant(aec_state.FullBandErleLog2()); 63 saturated_capture_ = saturated_capture_ || aec_state.SaturatedCapture(); 64 } else { 65 // Report the metrics over several frames in order to lower the impact of 66 // the logarithms involved on the computational complexity. 67 switch (block_counter_) { 68 case kMetricsCollectionBlocks + 1: 69 RTC_HISTOGRAM_BOOLEAN( 70 "WebRTC.Audio.EchoCanceller.UsableLinearEstimate", 71 static_cast<int>(aec_state.UsableLinearEstimate() ? 1 : 0)); 72 RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.FilterDelay", 73 aec_state.MinDirectPathFilterDelay(), 0, 30, 74 31); 75 RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.EchoCanceller.CaptureSaturation", 76 static_cast<int>(saturated_capture_ ? 1 : 0)); 77 break; 78 case kMetricsCollectionBlocks + 2: 79 RTC_HISTOGRAM_COUNTS_LINEAR( 80 "WebRTC.Audio.EchoCanceller.Erl.Value", 81 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, 82 erl_time_domain_.sum_value), 83 0, 59, 30); 84 RTC_HISTOGRAM_COUNTS_LINEAR( 85 "WebRTC.Audio.EchoCanceller.Erl.Max", 86 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, 87 erl_time_domain_.ceil_value), 88 0, 59, 30); 89 RTC_HISTOGRAM_COUNTS_LINEAR( 90 "WebRTC.Audio.EchoCanceller.Erl.Min", 91 aec3::TransformDbMetricForReporting(true, 0.f, 59.f, 30.f, 1.f, 92 erl_time_domain_.floor_value), 93 0, 59, 30); 94 break; 95 case kMetricsCollectionBlocks + 3: 96 RTC_HISTOGRAM_COUNTS_LINEAR( 97 "WebRTC.Audio.EchoCanceller.Erle.Value", 98 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, 99 erle_time_domain_.sum_value), 100 0, 19, 20); 101 RTC_HISTOGRAM_COUNTS_LINEAR( 102 "WebRTC.Audio.EchoCanceller.Erle.Max", 103 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, 104 erle_time_domain_.ceil_value), 105 0, 19, 20); 106 RTC_HISTOGRAM_COUNTS_LINEAR( 107 "WebRTC.Audio.EchoCanceller.Erle.Min", 108 aec3::TransformDbMetricForReporting(false, 0.f, 19.f, 0.f, 1.f, 109 erle_time_domain_.floor_value), 110 0, 19, 20); 111 metrics_reported_ = true; 112 RTC_DCHECK_EQ(kMetricsReportingIntervalBlocks, block_counter_); 113 block_counter_ = 0; 114 ResetMetrics(); 115 break; 116 default: 117 RTC_DCHECK_NOTREACHED(); 118 break; 119 } 120 } 121 } 122 123 namespace aec3 { 124 125 void UpdateDbMetric(const std::array<float, kFftLengthBy2Plus1>& value, 126 std::array<EchoRemoverMetrics::DbMetric, 2>* statistic) { 127 RTC_DCHECK(statistic); 128 // Truncation is intended in the band width computation. 129 constexpr int kNumBands = 2; 130 constexpr int kBandWidth = 65 / kNumBands; 131 constexpr float kOneByBandWidth = 1.f / kBandWidth; 132 RTC_DCHECK_EQ(kNumBands, statistic->size()); 133 RTC_DCHECK_EQ(65, value.size()); 134 for (size_t k = 0; k < statistic->size(); ++k) { 135 float average_band = 136 std::accumulate(value.begin() + kBandWidth * k, 137 value.begin() + kBandWidth * (k + 1), 0.f) * 138 kOneByBandWidth; 139 (*statistic)[k].Update(average_band); 140 } 141 } 142 143 int TransformDbMetricForReporting(bool negate, 144 float min_value, 145 float max_value, 146 float offset, 147 float scaling, 148 float value) { 149 float new_value = 10.f * std::log10(value * scaling + 1e-10f) + offset; 150 if (negate) { 151 new_value = -new_value; 152 } 153 return static_cast<int>(SafeClamp(new_value, min_value, max_value)); 154 } 155 156 } // namespace aec3 157 158 } // namespace webrtc