Chromium Code Reviews| Index: webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc | 
| diff --git a/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..141e70d164df66877f9230ce8b575df6108b6df6 | 
| --- /dev/null | 
| +++ b/webrtc/modules/audio_processing/aec3/echo_remover_metrics.cc | 
| @@ -0,0 +1,249 @@ | 
| +/* | 
| + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 
| + * | 
| + * Use of this source code is governed by a BSD-style license | 
| + * that can be found in the LICENSE file in the root of the source | 
| + * tree. An additional intellectual property rights grant can be found | 
| + * in the file PATENTS. All contributing project authors may | 
| + * be found in the AUTHORS file in the root of the source tree. | 
| + */ | 
| + | 
| +#include "webrtc/modules/audio_processing/aec3/echo_remover_metrics.h" | 
| + | 
| +#include <math.h> | 
| +#include <algorithm> | 
| +#include <numeric> | 
| + | 
| +#include "webrtc/system_wrappers/include/metrics.h" | 
| + | 
| +namespace webrtc { | 
| + | 
| +namespace { | 
| + | 
| +constexpr float kOneByMetricsCollectionBlocks = 1.f / kMetricsCollectionBlocks; | 
| + | 
| +} // namespace | 
| + | 
| +EchoRemoverMetrics::DbMetric::DbMetric() : DbMetric(0.f, 0.f, 0.f) {} | 
| +EchoRemoverMetrics::DbMetric::DbMetric(float sum_value, | 
| + float floor_value, | 
| + float ceil_value) | 
| + : sum_value(sum_value), floor_value(floor_value), ceil_value(ceil_value) {} | 
| + | 
| +void EchoRemoverMetrics::DbMetric::Update(float value) { | 
| + sum_value += value; | 
| + floor_value = std::min(floor_value, value); | 
| + ceil_value = std::max(ceil_value, value); | 
| +} | 
| + | 
| +void EchoRemoverMetrics::DbMetric::FormatForReporting(bool negate, | 
| + float min_value, | 
| + float max_value, | 
| + float offset, | 
| + float scaling) { | 
| + aec3::TransformDbMetricForReporting(negate, min_value, max_value, offset, | 
| + scaling * kOneByMetricsCollectionBlocks, | 
| + &sum_value); | 
| + aec3::TransformDbMetricForReporting(negate, min_value, max_value, offset, | 
| + scaling, &ceil_value); | 
| + aec3::TransformDbMetricForReporting(negate, min_value, max_value, offset, | 
| + scaling, &floor_value); | 
| +} | 
| + | 
| +EchoRemoverMetrics::EchoRemoverMetrics() { | 
| + ResetMetrics(); | 
| +} | 
| + | 
| +void EchoRemoverMetrics::ResetMetrics() { | 
| + erl_.fill(DbMetric(0.f, 10000.f, 0.000f)); | 
| + erle_.fill(DbMetric(0.f, 0.f, 1000.f)); | 
| + comfort_noise_.fill(DbMetric(0.f, 100000000.f, 0.f)); | 
| + suppressor_gain_.fill(DbMetric(0.f, 1.f, 0.f)); | 
| + active_render_ = 0; | 
| + saturated_capture_ = false; | 
| +} | 
| + | 
| +void EchoRemoverMetrics::Update( | 
| + const AecState& aec_state, | 
| + const std::array<float, kFftLengthBy2Plus1>& comfort_noise_spectrum, | 
| + const std::array<float, kFftLengthBy2Plus1>& suppressor_gain) { | 
| + if (++block_counter_ <= kMetricsCollectionBlocks) { | 
| + aec3::UpdateDbMetric(aec_state.Erl(), &erl_); | 
| + aec3::UpdateDbMetric(aec_state.Erle(), &erle_); | 
| + aec3::UpdateDbMetric(comfort_noise_spectrum, &comfort_noise_); | 
| + aec3::UpdateDbMetric(suppressor_gain, &suppressor_gain_); | 
| + active_render_ += (aec_state.ActiveRender() ? 1 : 0); | 
| 
 
hlundin-webrtc
2017/02/28 10:04:23
active_render_count_
 
peah-webrtc
2017/02/28 12:57:25
Done.
 
 | 
| + saturated_capture_ = saturated_capture_ || aec_state.SaturatedCapture(); | 
| + } else { | 
| + // Report the metrics over several frames in order to lower the impact of | 
| + // the logarithms involved on the computational complexity. | 
| + constexpr int kMetricsCollectionBlocksBy2 = kMetricsCollectionBlocks / 2; | 
| + constexpr float kComfortNoiseScaling = 1.f / (kBlockSize * kBlockSize); | 
| + switch (block_counter_) { | 
| + case kMetricsCollectionBlocks + 1: | 
| + erle_[0].FormatForReporting(true, 0.f, 19.f, 0.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageErleBand0", | 
| + static_cast<int>(erle_[0].sum_value), 0, 19, 20); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxErleBand0", | 
| + static_cast<int>(erle_[0].ceil_value), 0, | 
| + 19, 20); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MinErleBand0", | 
| + static_cast<int>(erle_[0].floor_value), 0, | 
| + 19, 20); | 
| + break; | 
| + case kMetricsCollectionBlocks + 2: | 
| + erle_[1].FormatForReporting(true, 0.f, 19.f, 0.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageErleBand1", | 
| + static_cast<int>(erle_[1].sum_value), 0, 19, 20); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxErleBand1", | 
| + static_cast<int>(erle_[1].ceil_value), 0, | 
| + 19, 20); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MinErleBand1", | 
| + static_cast<int>(erle_[1].floor_value), 0, | 
| + 19, 20); | 
| + break; | 
| + case kMetricsCollectionBlocks + 3: | 
| + erl_[0].FormatForReporting(true, 0.f, 59.f, 30.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageErlBand0", | 
| + static_cast<int>(erl_[0].sum_value), 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxErlBand0", | 
| + static_cast<int>(erl_[0].ceil_value), 0, 59, | 
| + 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MinErlBand0", | 
| + static_cast<int>(erl_[0].floor_value), 0, | 
| + 59, 30); | 
| + break; | 
| + case kMetricsCollectionBlocks + 4: | 
| + erl_[1].FormatForReporting(true, 0.f, 59.f, 30.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageErlBand1", | 
| + static_cast<int>(erl_[1].sum_value), 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MaxErlBand1", | 
| + static_cast<int>(erl_[1].ceil_value), 0, 59, | 
| + 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR("WebRTC.Audio.EchoCanceller.MinErlBand1", | 
| + static_cast<int>(erl_[1].floor_value), 0, | 
| + 59, 30); | 
| + break; | 
| + case kMetricsCollectionBlocks + 5: | 
| + comfort_noise_[0].FormatForReporting(true, 0.f, 89.f, -90.3f, | 
| + kComfortNoiseScaling); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageComfortNoiseBand0", | 
| + comfort_noise_[0].sum_value, 0, 89, 45); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MaxComfortNoiseBand0", | 
| + comfort_noise_[0].ceil_value, 0, 89, 45); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MinComfortNoiseBand0", | 
| + comfort_noise_[0].floor_value, 0, 89, 45); | 
| + break; | 
| + case kMetricsCollectionBlocks + 6: | 
| + comfort_noise_[1].FormatForReporting(true, 0.f, 89.f, -90.3f, | 
| + kComfortNoiseScaling); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageComfortNoiseBand1", | 
| + comfort_noise_[1].sum_value, 0, 89, 45); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MaxComfortNoiseBand1", | 
| + comfort_noise_[1].ceil_value, 0, 89, 45); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MinComfortNoiseBand1", | 
| + comfort_noise_[1].floor_value, 0, 89, 45); | 
| + break; | 
| + case kMetricsCollectionBlocks + 7: | 
| + suppressor_gain_[0].FormatForReporting(true, 0.f, 59.f, 0.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageSuppressorGainBand0", | 
| + suppressor_gain_[0].sum_value, 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MaxSuppressorGainBand0", | 
| + suppressor_gain_[0].ceil_value, 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MinSuppressorGainBand0", | 
| + suppressor_gain_[0].floor_value, 0, 59, 30); | 
| + break; | 
| + case kMetricsCollectionBlocks + 8: | 
| + suppressor_gain_[1].FormatForReporting(true, 0.f, 59.f, 0.f, 1.f); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.AverageSuppressorGainBand1", | 
| + suppressor_gain_[1].sum_value, 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MaxSuppressorGainBand1", | 
| + suppressor_gain_[1].ceil_value, 0, 59, 30); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.MinSuppressorGainBand1", | 
| + suppressor_gain_[1].floor_value, 0, 59, 30); | 
| + break; | 
| + case kMetricsCollectionBlocks + 9: | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.UsableLinearEstimate", | 
| + aec_state.UsableLinearEstimate() ? 1 : 0, 0, 1, 2); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.ModelBasedAecFeasible", | 
| + aec_state.ModelBasedAecFeasible() ? 1 : 0, 0, 1, 2); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.ActiveRender", | 
| + active_render_ > kMetricsCollectionBlocksBy2 ? 1 : 0, 0, 1, 2); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.FilterDelay", | 
| + aec_state.FilterDelay() ? *aec_state.FilterDelay() + 1 : 0, 0, 30, | 
| + 31); | 
| + RTC_HISTOGRAM_COUNTS_LINEAR( | 
| + "WebRTC.Audio.EchoCanceller.CaptureSaturation", | 
| + saturated_capture_ ? 1 : 0, 0, 1, 2); | 
| + metric_reported_ = true; | 
| + break; | 
| + case kMetricsCollectionBlocks + 10: | 
| + RTC_DCHECK_EQ(kMetricsReportingInterval, block_counter_); | 
| 
 
hlundin-webrtc
2017/02/28 10:04:23
So every 11 times you are not reporting anything.
 
peah-webrtc
2017/02/28 12:57:26
Done.
 
 | 
| + block_counter_ = 0; | 
| + ResetMetrics(); | 
| + metric_reported_ = false; | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| + break; | 
| + } | 
| + } | 
| +} | 
| + | 
| +namespace aec3 { | 
| + | 
| +void UpdateDbMetric(const std::array<float, kFftLengthBy2Plus1>& value, | 
| + std::array<EchoRemoverMetrics::DbMetric, 2>* statistic) { | 
| + RTC_DCHECK(statistic); | 
| + // Truncation is intended in the band width computation. | 
| + constexpr int kNumBands = 2; | 
| + constexpr int kBandWidth = 65 / kNumBands; | 
| + constexpr float kOneByBandWidth = 1.f / kBandWidth; | 
| + RTC_DCHECK_EQ(kNumBands, statistic->size()); | 
| + RTC_DCHECK_EQ(65, value.size()); | 
| + for (size_t k = 0; k < statistic->size(); ++k) { | 
| + float average_band = | 
| + std::accumulate(value.begin() + kBandWidth * k, | 
| + value.begin() + kBandWidth * (k + 1), 0.f) * | 
| + kOneByBandWidth; | 
| + (*statistic)[k].Update(average_band); | 
| + } | 
| +} | 
| + | 
| +void TransformDbMetricForReporting(bool negate, | 
| 
 
hlundin-webrtc
2017/02/28 10:04:23
I'm not fond of this method altering the value. Ca
 
peah-webrtc
2017/02/28 12:57:26
Done.
 
 | 
| + float min_value, | 
| + float max_value, | 
| + float offset, | 
| + float scaleing, | 
| 
 
hlundin-webrtc
2017/02/28 10:04:23
scaleing -> scaling
 
peah-webrtc
2017/02/28 12:57:26
Done.
 
 | 
| + float* value) { | 
| + RTC_DCHECK(value); | 
| + *value = 10.f * log10((*value) * scaleing + 1e-10f) + offset; | 
| + if (negate) { | 
| + *value = -*value; | 
| + } | 
| + *value = std::max(min_value, std::min(max_value, *value)); | 
| +} | 
| + | 
| +} // namespace aec3 | 
| + | 
| +} // namespace webrtc |