Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <stddef.h> | 7 #include <stddef.h> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 41 "googExperimentalNoiseSuppression"; | 41 "googExperimentalNoiseSuppression"; |
| 42 const char MediaAudioConstraints::kGoogBeamforming[] = "googBeamforming"; | 42 const char MediaAudioConstraints::kGoogBeamforming[] = "googBeamforming"; |
| 43 const char MediaAudioConstraints::kGoogArrayGeometry[] = "googArrayGeometry"; | 43 const char MediaAudioConstraints::kGoogArrayGeometry[] = "googArrayGeometry"; |
| 44 const char MediaAudioConstraints::kGoogHighpassFilter[] = "googHighpassFilter"; | 44 const char MediaAudioConstraints::kGoogHighpassFilter[] = "googHighpassFilter"; |
| 45 const char MediaAudioConstraints::kGoogTypingNoiseDetection[] = | 45 const char MediaAudioConstraints::kGoogTypingNoiseDetection[] = |
| 46 "googTypingNoiseDetection"; | 46 "googTypingNoiseDetection"; |
| 47 const char MediaAudioConstraints::kGoogAudioMirroring[] = "googAudioMirroring"; | 47 const char MediaAudioConstraints::kGoogAudioMirroring[] = "googAudioMirroring"; |
| 48 | 48 |
| 49 namespace { | 49 namespace { |
| 50 | 50 |
| 51 // The interval of which the AEC stats update functions should be called. This | |
| 52 // is the buffer size that the AP and AEC work on. | |
| 53 const int kChunkDurationMs = 10; | |
|
tommi (sloooow) - chröme
2016/06/28 11:43:56
If this value is defined somewhere else (as I susp
Henrik Grunell
2016/06/29 08:47:58
It is! In AudioProcessing. :) Done.
| |
| 54 | |
| 51 // Controls whether the hotword audio stream is used on supported platforms. | 55 // Controls whether the hotword audio stream is used on supported platforms. |
| 52 const char kMediaStreamAudioHotword[] = "googHotword"; | 56 const char kMediaStreamAudioHotword[] = "googHotword"; |
| 53 | 57 |
| 54 // Constant constraint keys which enables default audio constraints on | 58 // Constant constraint keys which enables default audio constraints on |
| 55 // mediastreams with audio. | 59 // mediastreams with audio. |
| 56 struct { | 60 struct { |
| 57 const char* key; | 61 const char* key; |
| 58 bool value; | 62 bool value; |
| 59 } const kDefaultAudioConstraints[] = { | 63 } const kDefaultAudioConstraints[] = { |
| 60 { MediaAudioConstraints::kEchoCancellation, true }, | 64 { MediaAudioConstraints::kEchoCancellation, true }, |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 std::string the_value; | 297 std::string the_value; |
| 294 if (GetConstraintValueAsString( | 298 if (GetConstraintValueAsString( |
| 295 constraints_, &blink::WebMediaTrackConstraintSet::googArrayGeometry, | 299 constraints_, &blink::WebMediaTrackConstraintSet::googArrayGeometry, |
| 296 &the_value)) { | 300 &the_value)) { |
| 297 return the_value; | 301 return the_value; |
| 298 } | 302 } |
| 299 return ""; | 303 return ""; |
| 300 } | 304 } |
| 301 | 305 |
| 302 EchoInformation::EchoInformation() | 306 EchoInformation::EchoInformation() |
| 303 : num_chunks_(0), echo_frames_received_(false) { | 307 : delay_stats_time_ms_(0), |
| 308 echo_frames_received_(false), | |
| 309 divergent_filter_stats_time_ms_(0), | |
| 310 num_divergent_filter_fraction_(0), | |
| 311 num_non_zero_divergent_filter_fraction_(0) {} | |
| 312 | |
| 313 EchoInformation::~EchoInformation() { | |
| 314 ReportAndResetAecDivergentFilterStats(); | |
| 304 } | 315 } |
| 305 | 316 |
| 306 EchoInformation::~EchoInformation() {} | |
| 307 | |
| 308 void EchoInformation::UpdateAecDelayStats( | 317 void EchoInformation::UpdateAecDelayStats( |
| 309 webrtc::EchoCancellation* echo_cancellation) { | 318 webrtc::EchoCancellation* echo_cancellation) { |
| 310 // Only start collecting stats if we know echo cancellation has measured an | 319 // Only start collecting stats if we know echo cancellation has measured an |
| 311 // echo. Otherwise we clutter the stats with for example cases where only the | 320 // echo. Otherwise we clutter the stats with for example cases where only the |
| 312 // microphone is used. | 321 // microphone is used. |
| 313 if (!echo_frames_received_ & !echo_cancellation->stream_has_echo()) | 322 if (!echo_frames_received_ & !echo_cancellation->stream_has_echo()) |
| 314 return; | 323 return; |
| 315 | 324 |
| 316 echo_frames_received_ = true; | 325 echo_frames_received_ = true; |
| 317 // In WebRTC, three echo delay metrics are calculated and updated every | 326 // In WebRTC, three echo delay metrics are calculated and updated every |
| 318 // five seconds. We use one of them, |fraction_poor_delays| to log in a UMA | 327 // five seconds. We use one of them, |fraction_poor_delays| to log in a UMA |
| 319 // histogram an Echo Cancellation quality metric. The stat in WebRTC has a | 328 // histogram an Echo Cancellation quality metric. The stat in WebRTC has a |
| 320 // fixed aggregation window of five seconds, so we use the same query | 329 // fixed aggregation window of five seconds, so we use the same query |
| 321 // frequency to avoid logging old values. | 330 // frequency to avoid logging old values. |
| 322 const int kNumChunksInFiveSeconds = 500; | |
| 323 if (!echo_cancellation->is_delay_logging_enabled() || | 331 if (!echo_cancellation->is_delay_logging_enabled() || |
| 324 !echo_cancellation->is_enabled()) { | 332 !echo_cancellation->is_enabled()) { |
| 325 return; | 333 return; |
| 326 } | 334 } |
| 327 | 335 |
| 328 num_chunks_++; | 336 delay_stats_time_ms_ += kChunkDurationMs; |
| 329 if (num_chunks_ < kNumChunksInFiveSeconds) { | 337 if (delay_stats_time_ms_ < 500 * kChunkDurationMs) // 5 seconds |
| 330 return; | 338 return; |
| 331 } | |
| 332 | 339 |
| 333 int dummy_median = 0, dummy_std = 0; | 340 int dummy_median = 0, dummy_std = 0; |
| 334 float fraction_poor_delays = 0; | 341 float fraction_poor_delays = 0; |
| 335 if (echo_cancellation->GetDelayMetrics( | 342 if (echo_cancellation->GetDelayMetrics( |
| 336 &dummy_median, &dummy_std, &fraction_poor_delays) == | 343 &dummy_median, &dummy_std, &fraction_poor_delays) == |
| 337 webrtc::AudioProcessing::kNoError) { | 344 webrtc::AudioProcessing::kNoError) { |
| 338 num_chunks_ = 0; | 345 delay_stats_time_ms_ = 0; |
| 339 // Map |fraction_poor_delays| to an Echo Cancellation quality and log in UMA | 346 // Map |fraction_poor_delays| to an Echo Cancellation quality and log in UMA |
| 340 // histogram. See DelayBasedEchoQuality for information on histogram | 347 // histogram. See DelayBasedEchoQuality for information on histogram |
| 341 // buckets. | 348 // buckets. |
| 342 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality", | 349 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality", |
| 343 EchoDelayFrequencyToQuality(fraction_poor_delays), | 350 EchoDelayFrequencyToQuality(fraction_poor_delays), |
| 344 DELAY_BASED_ECHO_QUALITY_MAX); | 351 DELAY_BASED_ECHO_QUALITY_MAX); |
| 345 } | 352 } |
| 346 } | 353 } |
| 347 | 354 |
| 355 void EchoInformation::UpdateAecDivergentFilterStats( | |
| 356 webrtc::EchoCancellation* echo_cancellation) { | |
| 357 if (!echo_cancellation->is_enabled() || | |
| 358 !echo_cancellation->are_metrics_enabled()) { | |
| 359 return; | |
| 360 } | |
| 361 | |
| 362 divergent_filter_stats_time_ms_ += kChunkDurationMs; | |
| 363 if (divergent_filter_stats_time_ms_ < 100 * kChunkDurationMs) // 1 second | |
| 364 return; | |
| 365 | |
| 366 webrtc::EchoCancellation::Metrics metrics; | |
| 367 if (echo_cancellation->GetMetrics(&metrics) == | |
| 368 webrtc::AudioProcessing::kNoError) { | |
| 369 // If not yet calculated, |metrics.divergent_filter_fraction| is -1.0. After | |
| 370 // being calculated the first time, it is updated periodically. | |
| 371 if (metrics.divergent_filter_fraction < 0.0f) { | |
| 372 DCHECK_EQ(num_divergent_filter_fraction_, 0); | |
| 373 return; | |
| 374 } | |
| 375 if (metrics.divergent_filter_fraction > 0.0f) { | |
| 376 ++num_non_zero_divergent_filter_fraction_; | |
| 377 } | |
| 378 } else { | |
| 379 DLOG(WARNING) << "Get echo cancellation metrics failed."; | |
| 380 } | |
| 381 ++num_divergent_filter_fraction_; | |
| 382 divergent_filter_stats_time_ms_ = 0; | |
| 383 } | |
| 384 | |
| 385 void EchoInformation::ReportAndResetAecDivergentFilterStats() { | |
|
tommi (sloooow) - chröme
2016/06/28 11:43:56
can you add thread checks to these methods? As is,
Henrik Grunell
2016/06/29 08:47:58
Hmm, they are not accessed on the same thread. Tha
| |
| 386 if (num_divergent_filter_fraction_ == 0) | |
| 387 return; | |
| 388 | |
| 389 int non_zero_percent = 100 * num_non_zero_divergent_filter_fraction_ / | |
| 390 num_divergent_filter_fraction_; | |
| 391 UMA_HISTOGRAM_PERCENTAGE("WebRTC.AecFilterHasDivergence", | |
| 392 non_zero_percent); | |
| 393 | |
| 394 divergent_filter_stats_time_ms_ = 0; | |
| 395 num_non_zero_divergent_filter_fraction_ = 0; | |
| 396 num_divergent_filter_fraction_ = 0; | |
| 397 } | |
| 398 | |
| 348 void EnableEchoCancellation(AudioProcessing* audio_processing) { | 399 void EnableEchoCancellation(AudioProcessing* audio_processing) { |
| 349 #if defined(OS_ANDROID) | 400 #if defined(OS_ANDROID) |
| 350 // Mobile devices are using AECM. | 401 // Mobile devices are using AECM. |
| 351 CHECK_EQ(0, audio_processing->echo_control_mobile()->set_routing_mode( | 402 CHECK_EQ(0, audio_processing->echo_control_mobile()->set_routing_mode( |
| 352 webrtc::EchoControlMobile::kSpeakerphone)); | 403 webrtc::EchoControlMobile::kSpeakerphone)); |
| 353 CHECK_EQ(0, audio_processing->echo_control_mobile()->Enable(true)); | 404 CHECK_EQ(0, audio_processing->echo_control_mobile()->Enable(true)); |
| 354 return; | 405 return; |
| 355 #endif | 406 #endif |
| 356 int err = audio_processing->echo_cancellation()->set_suppression_level( | 407 int err = audio_processing->echo_cancellation()->set_suppression_level( |
| 357 webrtc::EchoCancellation::kHighSuppression); | 408 webrtc::EchoCancellation::kHighSuppression); |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 466 | 517 |
| 467 // Give preference to the audio constraint over the device-supplied mic | 518 // Give preference to the audio constraint over the device-supplied mic |
| 468 // positions. This is mainly for testing purposes. | 519 // positions. This is mainly for testing purposes. |
| 469 return WebrtcPointsFromMediaPoints( | 520 return WebrtcPointsFromMediaPoints( |
| 470 constraints_geometry.empty() | 521 constraints_geometry.empty() |
| 471 ? input_params.mic_positions | 522 ? input_params.mic_positions |
| 472 : media::ParsePointsFromString(constraints_geometry)); | 523 : media::ParsePointsFromString(constraints_geometry)); |
| 473 } | 524 } |
| 474 | 525 |
| 475 } // namespace content | 526 } // namespace content |
| OLD | NEW |