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

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: Updated comment 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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 { kMediaStreamAudioHotword, false }, 71 { kMediaStreamAudioHotword, false },
73 }; 72 };
74 73
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_INVALID = 0,
82 DELAY_BASED_ECHO_QUALITY_GOOD,
83 DELAY_BASED_ECHO_QUALITY_SPURIOUS, 83 DELAY_BASED_ECHO_QUALITY_SPURIOUS,
84 DELAY_BASED_ECHO_QUALITY_BAD, 84 DELAY_BASED_ECHO_QUALITY_BAD,
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_INVALID
92 // delay_frequency is negative which happens if we have insufficient data.
91 // DELAY_BASED_ECHO_QUALITY_GOOD 93 // DELAY_BASED_ECHO_QUALITY_GOOD
92 // delay is out of bounds during at most 10 % of the time. 94 // delay is out of bounds during at most 10 % of the time.
93 // DELAY_BASED_ECHO_QUALITY_SPURIOUS 95 // DELAY_BASED_ECHO_QUALITY_SPURIOUS
94 // delay is out of bounds 10-80 % of the time. 96 // delay is out of bounds 10-80 % of the time.
95 // DELAY_BASED_ECHO_QUALITY_BAD 97 // DELAY_BASED_ECHO_QUALITY_BAD
96 // delay is mostly out of bounds >= 80 % of the time. 98 // delay is mostly out of bounds >= 80 % of the time.
97 if (delay_frequency <= kEchoDelayFrequencyLowerLimit) 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(AudioProcessing* audio_processing) {
perkj_chrome 2015/02/09 07:53:13 It looks like this argument should be the type of
bjornv 2015/02/09 11:11:16 Much better. Done
224 // One way to get an indication of how well the echo cancellation performs is 228 // In WebRTC three echo delay metrics are calculated and updated every second.
perkj_chrome 2015/02/09 07:53:13 nit In WebRTC, three echo ...
bjornv 2015/02/09 11:11:16 Done.
225 // to compare the, by AEC, estimated delay with the AEC filter length. 229 // We use one of them, |fraction_poor_delays|, but aggregate over 5 seconds to
226 // |kMaxAecFilterLengthMs| is the maximum delay we can allow before we 230 // log in a UMA histogram to monitor Echo Cancellation quality. Since the stat
227 // consider the AEC to fail. This value should not be larger than the filter 231 // in WebRTC has a fixed aggregation window of one second we query the stat
228 // length used inside AEC. This is for now set to match the extended filter 232 // every second and average over 5 such queries.
229 // mode which is turned on for all platforms. 233 // WebRTC process audio in 10 ms chunks.
230 const int kMaxAecFilterLengthMs = 128; 234 const int kNumChunksInOneSecond = 100;
231 if ((delay < -2) || (delay > kMaxAecFilterLengthMs)) { 235 if (!audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
232 // The |delay| is out of bounds which indicates that the echo cancellation 236 !audio_processing->echo_cancellation()->is_enabled()) {
233 // filter can not handle the echo. Hence, we have a potential full echo 237 return;
234 // case. |delay| values {-1, -2} are reserved for errors.
235 ++echo_poor_delay_counts_;
236 } 238 }
237 ++echo_total_delay_counts_; 239
240 num_chunks_++;
241 if (num_chunks_ < kNumChunksInOneSecond) {
242 return;
243 }
244
245 int dummy_median = 0, dummy_std = 0;
246 float fraction_poor_delays = 0;
247 if (!audio_processing->echo_cancellation()->GetDelayMetrics(
248 &dummy_median, &dummy_std, &fraction_poor_delays)) {
249 echo_fraction_poor_delays_ += fraction_poor_delays;
250 num_queries_++;
251 num_chunks_ = 0;
252 }
238 LogAecDelayStats(); 253 LogAecDelayStats();
239 } 254 }
240 255
241 void EchoInformation::LogAecDelayStats() { 256 void EchoInformation::LogAecDelayStats() {
242 // We update the UMA statistics every 5 seconds. 257 // We update the UMA statistics every 5 seconds.
243 const int kTimeBetweenLogsInSeconds = 5; 258 const int kNumQueriesIn5Seconds = 5;
244 const base::TimeDelta time_since_last_log = 259 if (num_queries_ < kNumQueriesIn5Seconds) {
245 base::TimeTicks::Now() - last_log_time_;
246 if (time_since_last_log.InSeconds() < kTimeBetweenLogsInSeconds)
247 return; 260 return;
261 }
248 262
249 // Calculate how frequent the AEC delay was out of bounds since last time we 263 // 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 264 // updated UMA histograms by averaging |echo_fraction_poor_delays_| over
251 // buckets; see DelayBasedEchoQuality. 265 // |num_queries_|. Then store the result into one of four histogram buckets;
252 float poor_delay_frequency = 0.f; 266 // see DelayBasedEchoQuality.
253 if (echo_total_delay_counts_ > 0) { 267 float poor_delay_frequency = echo_fraction_poor_delays_ / num_queries_;
254 poor_delay_frequency = static_cast<float>(echo_poor_delay_counts_) / 268 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
255 static_cast<float>(echo_total_delay_counts_); 269 EchoDelayFrequencyToQuality(poor_delay_frequency),
256 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality", 270 DELAY_BASED_ECHO_QUALITY_MAX);
257 EchoDelayFrequencyToQuality(poor_delay_frequency), 271 num_queries_ = 0;
258 DELAY_BASED_ECHO_QUALITY_MAX); 272 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 } 273 }
264 274
265 void EnableEchoCancellation(AudioProcessing* audio_processing) { 275 void EnableEchoCancellation(AudioProcessing* audio_processing) {
266 #if defined(OS_ANDROID) || defined(OS_IOS) 276 #if defined(OS_ANDROID) || defined(OS_IOS)
267 const std::string group_name = 277 const std::string group_name =
268 base::FieldTrialList::FindFullName("ReplaceAECMWithAEC"); 278 base::FieldTrialList::FindFullName("ReplaceAECMWithAEC");
269 if (group_name.empty() || 279 if (group_name.empty() ||
270 !(group_name == "Enabled" || group_name == "DefaultEnabled")) { 280 !(group_name == "Enabled" || group_name == "DefaultEnabled")) {
271 // Mobile devices are using AECM. 281 // Mobile devices are using AECM.
272 int err = audio_processing->echo_control_mobile()->set_routing_mode( 282 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); 348 CHECK_EQ(err, 0);
339 } 349 }
340 350
341 void GetAecStats(AudioProcessing* audio_processing, 351 void GetAecStats(AudioProcessing* audio_processing,
342 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) { 352 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
343 // These values can take on valid negative values, so use the lowest possible 353 // These values can take on valid negative values, so use the lowest possible
344 // level as default rather than -1. 354 // level as default rather than -1.
345 stats->echo_return_loss = -100; 355 stats->echo_return_loss = -100;
346 stats->echo_return_loss_enhancement = -100; 356 stats->echo_return_loss_enhancement = -100;
347 357
348 // These values can also be negative, but in practice -1 is only used to 358 // 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 359 // signal insufficient data, since the resolution is limited to multiples
350 // of 4ms. 360 // of 4ms.
351 stats->echo_delay_median_ms = -1; 361 stats->echo_delay_median_ms = -1;
352 stats->echo_delay_std_ms = -1; 362 stats->echo_delay_std_ms = -1;
353 363
354 // TODO(ajm): Re-enable this metric once we have a reliable implementation. 364 // TODO(ajm): Re-enable this metric once we have a reliable implementation.
355 stats->aec_quality_min = -1.0f; 365 stats->aec_quality_min = -1.0f;
356 366
357 if (!audio_processing->echo_cancellation()->are_metrics_enabled() || 367 if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
358 !audio_processing->echo_cancellation()->is_delay_logging_enabled() || 368 !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
359 !audio_processing->echo_cancellation()->is_enabled()) { 369 !audio_processing->echo_cancellation()->is_enabled()) {
360 return; 370 return;
361 } 371 }
362 372
363 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary 373 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
364 // here, but it appears to be unsuitable currently. Revisit after this is 374 // here, but it appears to be unsuitable currently. Revisit after this is
365 // investigated: http://b/issue?id=5666755 375 // investigated: http://b/issue?id=5666755
366 webrtc::EchoCancellation::Metrics echo_metrics; 376 webrtc::EchoCancellation::Metrics echo_metrics;
367 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) { 377 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
368 stats->echo_return_loss = echo_metrics.echo_return_loss.instant; 378 stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
369 stats->echo_return_loss_enhancement = 379 stats->echo_return_loss_enhancement =
370 echo_metrics.echo_return_loss_enhancement.instant; 380 echo_metrics.echo_return_loss_enhancement.instant;
371 } 381 }
372 382
373 int median = 0, std = 0; 383 int median = 0, std = 0;
374 if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) { 384 float dummy = 0;
385 if (!audio_processing->echo_cancellation()->GetDelayMetrics(
386 &median, &std, &dummy)) {
375 stats->echo_delay_median_ms = median; 387 stats->echo_delay_median_ms = median;
376 stats->echo_delay_std_ms = std; 388 stats->echo_delay_std_ms = std;
377 } 389 }
378 } 390 }
379 391
380 } // namespace content 392 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698