Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: content/renderer/media/media_stream_audio_processor_options.cc

Issue 904203003: UMA histogram WebRTC.AecDelayBasedQuality updated (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed review comments by perkj@ Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/media_stream_audio_processor_options.h" 5 #include "content/renderer/media/media_stream_audio_processor_options.h"
6 6
7 #include "base/files/file_path.h" 7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h" 8 #include "base/files/file_util.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/field_trial.h" 10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/utf_string_conversions.h" 13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "content/common/media/media_stream_options.h" 14 #include "content/common/media/media_stream_options.h"
16 #include "content/renderer/media/media_stream_constraints_util.h" 15 #include "content/renderer/media/media_stream_constraints_util.h"
17 #include "content/renderer/media/media_stream_source.h" 16 #include "content/renderer/media/media_stream_source.h"
18 #include "content/renderer/media/rtc_media_constraints.h" 17 #include "content/renderer/media/rtc_media_constraints.h"
19 #include "media/audio/audio_parameters.h" 18 #include "media/audio/audio_parameters.h"
20 #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h " 19 #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h "
21 #include "third_party/webrtc/modules/audio_processing/typing_detection.h" 20 #include "third_party/webrtc/modules/audio_processing/typing_detection.h"
22 21
23 namespace content { 22 namespace content {
24 23
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
75 bool IsAudioProcessingConstraint(const std::string& key) { 74 bool IsAudioProcessingConstraint(const std::string& key) {
76 // |kMediaStreamAudioDucking| does not require audio processing. 75 // |kMediaStreamAudioDucking| does not require audio processing.
77 return key != kMediaStreamAudioDucking; 76 return key != kMediaStreamAudioDucking;
78 } 77 }
79 78
80 // Used to log echo quality based on delay estimates. 79 // Used to log echo quality based on delay estimates.
81 enum DelayBasedEchoQuality { 80 enum DelayBasedEchoQuality {
82 DELAY_BASED_ECHO_QUALITY_GOOD = 0, 81 DELAY_BASED_ECHO_QUALITY_GOOD = 0,
83 DELAY_BASED_ECHO_QUALITY_SPURIOUS, 82 DELAY_BASED_ECHO_QUALITY_SPURIOUS,
84 DELAY_BASED_ECHO_QUALITY_BAD, 83 DELAY_BASED_ECHO_QUALITY_BAD,
84 DELAY_BASED_ECHO_QUALITY_INVALID,
85 DELAY_BASED_ECHO_QUALITY_MAX 85 DELAY_BASED_ECHO_QUALITY_MAX
86 }; 86 };
87 87
88 DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) { 88 DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) {
89 const float kEchoDelayFrequencyLowerLimit = 0.1f; 89 const float kEchoDelayFrequencyLowerLimit = 0.1f;
90 const float kEchoDelayFrequencyUpperLimit = 0.8f; 90 const float kEchoDelayFrequencyUpperLimit = 0.8f;
91 // DELAY_BASED_ECHO_QUALITY_GOOD 91 // DELAY_BASED_ECHO_QUALITY_GOOD
92 // delay is out of bounds during at most 10 % of the time. 92 // delay is out of bounds during at most 10 % of the time.
93 // DELAY_BASED_ECHO_QUALITY_SPURIOUS 93 // DELAY_BASED_ECHO_QUALITY_SPURIOUS
94 // delay is out of bounds 10-80 % of the time. 94 // delay is out of bounds 10-80 % of the time.
95 // DELAY_BASED_ECHO_QUALITY_BAD 95 // DELAY_BASED_ECHO_QUALITY_BAD
96 // delay is mostly out of bounds >= 80 % of the time. 96 // delay is mostly out of bounds >= 80 % of the time.
97 if (delay_frequency <= kEchoDelayFrequencyLowerLimit) 97 // DELAY_BASED_ECHO_QUALITY_INVALID
98 // delay_frequency is negative which happens if we have insufficient data.
99 if (delay_frequency < 0)
100 return DELAY_BASED_ECHO_QUALITY_INVALID;
101 else if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
98 return DELAY_BASED_ECHO_QUALITY_GOOD; 102 return DELAY_BASED_ECHO_QUALITY_GOOD;
99 else if (delay_frequency < kEchoDelayFrequencyUpperLimit) 103 else if (delay_frequency < kEchoDelayFrequencyUpperLimit)
100 return DELAY_BASED_ECHO_QUALITY_SPURIOUS; 104 return DELAY_BASED_ECHO_QUALITY_SPURIOUS;
101 else 105 else
102 return DELAY_BASED_ECHO_QUALITY_BAD; 106 return DELAY_BASED_ECHO_QUALITY_BAD;
103 } 107 }
104 108
105 } // namespace 109 } // namespace
106 110
107 // TODO(xians): Remove this method after the APM in WebRtc is deprecated. 111 // TODO(xians): Remove this method after the APM in WebRtc is deprecated.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 211
208 for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) { 212 for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
209 if (kDefaultAudioConstraints[i].key == key) 213 if (kDefaultAudioConstraints[i].key == key)
210 return kDefaultAudioConstraints[i].value; 214 return kDefaultAudioConstraints[i].value;
211 } 215 }
212 216
213 return false; 217 return false;
214 } 218 }
215 219
216 EchoInformation::EchoInformation() 220 EchoInformation::EchoInformation()
217 : echo_poor_delay_counts_(0), 221 : num_chunks_(0),
218 echo_total_delay_counts_(0), 222 num_queries_(0),
219 last_log_time_(base::TimeTicks::Now()) {} 223 echo_fraction_poor_delays_(0.0f) {}
220 224
221 EchoInformation::~EchoInformation() {} 225 EchoInformation::~EchoInformation() {}
222 226
223 void EchoInformation::UpdateAecDelayStats(int delay) { 227 void EchoInformation::UpdateAecDelayStats(
224 // One way to get an indication of how well the echo cancellation performs is 228 webrtc::EchoCancellation* echo_cancellation) {
225 // to compare the, by AEC, estimated delay with the AEC filter length. 229 // In WebRTC, three echo delay metrics are calculated and updated every
226 // |kMaxAecFilterLengthMs| is the maximum delay we can allow before we 230 // second. We use one of them, |fraction_poor_delays|, but aggregate over
227 // consider the AEC to fail. This value should not be larger than the filter 231 // five seconds to log in a UMA histogram to monitor Echo Cancellation
228 // length used inside AEC. This is for now set to match the extended filter 232 // quality. Since the stat in WebRTC has a fixed aggregation window of one
229 // mode which is turned on for all platforms. 233 // second we query the stat every second and average over five such queries.
230 const int kMaxAecFilterLengthMs = 128; 234 // WebRTC process audio in 10 ms chunks.
231 if ((delay < -2) || (delay > kMaxAecFilterLengthMs)) { 235 const int kNumChunksInOneSecond = 100;
232 // The |delay| is out of bounds which indicates that the echo cancellation 236 if (!echo_cancellation->is_delay_logging_enabled() ||
233 // filter can not handle the echo. Hence, we have a potential full echo 237 !echo_cancellation->is_enabled()) {
234 // case. |delay| values {-1, -2} are reserved for errors. 238 return;
235 ++echo_poor_delay_counts_;
236 } 239 }
237 ++echo_total_delay_counts_; 240
241 num_chunks_++;
242 if (num_chunks_ < kNumChunksInOneSecond) {
243 return;
244 }
245
246 int dummy_median = 0, dummy_std = 0;
247 float fraction_poor_delays = 0;
248 if (!echo_cancellation->GetDelayMetrics(&dummy_median, &dummy_std,
perkj_chrome 2015/02/09 11:48:30 Not from this cl I see but it looks quite weird to
bjornv 2015/02/09 14:39:11 Agree. In fact Karl would have killed me for not c
249 &fraction_poor_delays)) {
250 echo_fraction_poor_delays_ += fraction_poor_delays;
251 num_queries_++;
252 num_chunks_ = 0;
253 }
238 LogAecDelayStats(); 254 LogAecDelayStats();
239 } 255 }
240 256
241 void EchoInformation::LogAecDelayStats() { 257 void EchoInformation::LogAecDelayStats() {
242 // We update the UMA statistics every 5 seconds. 258 // We update the UMA statistics every 5 seconds.
243 const int kTimeBetweenLogsInSeconds = 5; 259 const int kNumQueriesIn5Seconds = 5;
244 const base::TimeDelta time_since_last_log = 260 if (num_queries_ < kNumQueriesIn5Seconds) {
245 base::TimeTicks::Now() - last_log_time_;
246 if (time_since_last_log.InSeconds() < kTimeBetweenLogsInSeconds)
247 return; 261 return;
262 }
248 263
249 // Calculate how frequent the AEC delay was out of bounds since last time we 264 // Calculate how frequent the AEC delay was out of bounds since last time we
250 // updated UMA histograms. Then store the result into one of three histogram 265 // updated UMA histograms by averaging |echo_fraction_poor_delays_| over
251 // buckets; see DelayBasedEchoQuality. 266 // |num_queries_|. Then store the result into one of four histogram buckets;
252 float poor_delay_frequency = 0.f; 267 // see DelayBasedEchoQuality.
253 if (echo_total_delay_counts_ > 0) { 268 float poor_delay_frequency = echo_fraction_poor_delays_ / num_queries_;
254 poor_delay_frequency = static_cast<float>(echo_poor_delay_counts_) / 269 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
255 static_cast<float>(echo_total_delay_counts_); 270 EchoDelayFrequencyToQuality(poor_delay_frequency),
256 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality", 271 DELAY_BASED_ECHO_QUALITY_MAX);
257 EchoDelayFrequencyToQuality(poor_delay_frequency), 272 num_queries_ = 0;
258 DELAY_BASED_ECHO_QUALITY_MAX); 273 echo_fraction_poor_delays_ = 0.0f;
259 }
260 echo_poor_delay_counts_ = 0;
261 echo_total_delay_counts_ = 0;
262 last_log_time_ = base::TimeTicks::Now();
263 } 274 }
264 275
265 void EnableEchoCancellation(AudioProcessing* audio_processing) { 276 void EnableEchoCancellation(AudioProcessing* audio_processing) {
266 #if defined(OS_ANDROID) || defined(OS_IOS) 277 #if defined(OS_ANDROID) || defined(OS_IOS)
267 const std::string group_name = 278 const std::string group_name =
268 base::FieldTrialList::FindFullName("ReplaceAECMWithAEC"); 279 base::FieldTrialList::FindFullName("ReplaceAECMWithAEC");
269 if (group_name.empty() || 280 if (group_name.empty() ||
270 !(group_name == "Enabled" || group_name == "DefaultEnabled")) { 281 !(group_name == "Enabled" || group_name == "DefaultEnabled")) {
271 // Mobile devices are using AECM. 282 // Mobile devices are using AECM.
272 int err = audio_processing->echo_control_mobile()->set_routing_mode( 283 int err = audio_processing->echo_control_mobile()->set_routing_mode(
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 CHECK_EQ(err, 0); 349 CHECK_EQ(err, 0);
339 } 350 }
340 351
341 void GetAecStats(AudioProcessing* audio_processing, 352 void GetAecStats(AudioProcessing* audio_processing,
342 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) { 353 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
343 // These values can take on valid negative values, so use the lowest possible 354 // These values can take on valid negative values, so use the lowest possible
344 // level as default rather than -1. 355 // level as default rather than -1.
345 stats->echo_return_loss = -100; 356 stats->echo_return_loss = -100;
346 stats->echo_return_loss_enhancement = -100; 357 stats->echo_return_loss_enhancement = -100;
347 358
348 // These values can also be negative, but in practice -1 is only used to 359 // The median value can also be negative, but in practice -1 is only used to
349 // signal insufficient data, since the resolution is limited to multiples 360 // signal insufficient data, since the resolution is limited to multiples
350 // of 4ms. 361 // of 4ms.
351 stats->echo_delay_median_ms = -1; 362 stats->echo_delay_median_ms = -1;
352 stats->echo_delay_std_ms = -1; 363 stats->echo_delay_std_ms = -1;
353 364
354 // TODO(ajm): Re-enable this metric once we have a reliable implementation. 365 // TODO(ajm): Re-enable this metric once we have a reliable implementation.
355 stats->aec_quality_min = -1.0f; 366 stats->aec_quality_min = -1.0f;
356 367
357 if (!audio_processing->echo_cancellation()->are_metrics_enabled() || 368 if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
358 !audio_processing->echo_cancellation()->is_delay_logging_enabled() || 369 !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
359 !audio_processing->echo_cancellation()->is_enabled()) { 370 !audio_processing->echo_cancellation()->is_enabled()) {
360 return; 371 return;
361 } 372 }
362 373
363 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary 374 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
364 // here, but it appears to be unsuitable currently. Revisit after this is 375 // here, but it appears to be unsuitable currently. Revisit after this is
365 // investigated: http://b/issue?id=5666755 376 // investigated: http://b/issue?id=5666755
366 webrtc::EchoCancellation::Metrics echo_metrics; 377 webrtc::EchoCancellation::Metrics echo_metrics;
367 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) { 378 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
368 stats->echo_return_loss = echo_metrics.echo_return_loss.instant; 379 stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
369 stats->echo_return_loss_enhancement = 380 stats->echo_return_loss_enhancement =
370 echo_metrics.echo_return_loss_enhancement.instant; 381 echo_metrics.echo_return_loss_enhancement.instant;
371 } 382 }
372 383
373 int median = 0, std = 0; 384 int median = 0, std = 0;
374 if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) { 385 float dummy = 0;
386 if (!audio_processing->echo_cancellation()->GetDelayMetrics(
387 &median, &std, &dummy)) {
375 stats->echo_delay_median_ms = median; 388 stats->echo_delay_median_ms = median;
376 stats->echo_delay_std_ms = std; 389 stats->echo_delay_std_ms = std;
377 } 390 }
378 } 391 }
379 392
380 } // namespace content 393 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/media_stream_audio_processor_options.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698