| Index: content/renderer/media/media_stream_audio_processor_options.cc
|
| diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc
|
| index b2465b3350286d05a8f543b8c11bf04455a0bca5..ccba777e9549e7624308c38050debe3680df1bd7 100644
|
| --- a/content/renderer/media/media_stream_audio_processor_options.cc
|
| +++ b/content/renderer/media/media_stream_audio_processor_options.cc
|
| @@ -11,7 +11,6 @@
|
| #include "base/metrics/histogram.h"
|
| #include "base/strings/string_number_conversions.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| -#include "base/time/time.h"
|
| #include "content/common/media/media_stream_options.h"
|
| #include "content/renderer/media/media_stream_constraints_util.h"
|
| #include "content/renderer/media/media_stream_source.h"
|
| @@ -82,6 +81,7 @@ enum DelayBasedEchoQuality {
|
| DELAY_BASED_ECHO_QUALITY_GOOD = 0,
|
| DELAY_BASED_ECHO_QUALITY_SPURIOUS,
|
| DELAY_BASED_ECHO_QUALITY_BAD,
|
| + DELAY_BASED_ECHO_QUALITY_INVALID,
|
| DELAY_BASED_ECHO_QUALITY_MAX
|
| };
|
|
|
| @@ -94,7 +94,11 @@ DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) {
|
| // delay is out of bounds 10-80 % of the time.
|
| // DELAY_BASED_ECHO_QUALITY_BAD
|
| // delay is mostly out of bounds >= 80 % of the time.
|
| - if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
|
| + // DELAY_BASED_ECHO_QUALITY_INVALID
|
| + // delay_frequency is negative which happens if we have insufficient data.
|
| + if (delay_frequency < 0)
|
| + return DELAY_BASED_ECHO_QUALITY_INVALID;
|
| + else if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
|
| return DELAY_BASED_ECHO_QUALITY_GOOD;
|
| else if (delay_frequency < kEchoDelayFrequencyUpperLimit)
|
| return DELAY_BASED_ECHO_QUALITY_SPURIOUS;
|
| @@ -214,52 +218,60 @@ bool MediaAudioConstraints::GetDefaultValueForConstraint(
|
| }
|
|
|
| EchoInformation::EchoInformation()
|
| - : echo_poor_delay_counts_(0),
|
| - echo_total_delay_counts_(0),
|
| - last_log_time_(base::TimeTicks::Now()) {}
|
| + : num_chunks_(0),
|
| + num_queries_(0),
|
| + echo_fraction_poor_delays_(0.0f) {}
|
|
|
| EchoInformation::~EchoInformation() {}
|
|
|
| -void EchoInformation::UpdateAecDelayStats(int delay) {
|
| - // One way to get an indication of how well the echo cancellation performs is
|
| - // to compare the, by AEC, estimated delay with the AEC filter length.
|
| - // |kMaxAecFilterLengthMs| is the maximum delay we can allow before we
|
| - // consider the AEC to fail. This value should not be larger than the filter
|
| - // length used inside AEC. This is for now set to match the extended filter
|
| - // mode which is turned on for all platforms.
|
| - const int kMaxAecFilterLengthMs = 128;
|
| - if ((delay < -2) || (delay > kMaxAecFilterLengthMs)) {
|
| - // The |delay| is out of bounds which indicates that the echo cancellation
|
| - // filter can not handle the echo. Hence, we have a potential full echo
|
| - // case. |delay| values {-1, -2} are reserved for errors.
|
| - ++echo_poor_delay_counts_;
|
| +void EchoInformation::UpdateAecDelayStats(
|
| + webrtc::EchoCancellation* echo_cancellation) {
|
| + // In WebRTC, three echo delay metrics are calculated and updated every
|
| + // second. We use one of them, |fraction_poor_delays|, but aggregate over
|
| + // five seconds to log in a UMA histogram to monitor Echo Cancellation
|
| + // quality. Since the stat in WebRTC has a fixed aggregation window of one
|
| + // second we query the stat every second and average over five such queries.
|
| + // WebRTC process audio in 10 ms chunks.
|
| + const int kNumChunksInOneSecond = 100;
|
| + if (!echo_cancellation->is_delay_logging_enabled() ||
|
| + !echo_cancellation->is_enabled()) {
|
| + return;
|
| + }
|
| +
|
| + num_chunks_++;
|
| + if (num_chunks_ < kNumChunksInOneSecond) {
|
| + return;
|
| + }
|
| +
|
| + int dummy_median = 0, dummy_std = 0;
|
| + float fraction_poor_delays = 0;
|
| + if (echo_cancellation->GetDelayMetrics(
|
| + &dummy_median, &dummy_std, &fraction_poor_delays) ==
|
| + webrtc::AudioProcessing::kNoError) {
|
| + echo_fraction_poor_delays_ += fraction_poor_delays;
|
| + num_queries_++;
|
| + num_chunks_ = 0;
|
| }
|
| - ++echo_total_delay_counts_;
|
| LogAecDelayStats();
|
| }
|
|
|
| void EchoInformation::LogAecDelayStats() {
|
| // We update the UMA statistics every 5 seconds.
|
| - const int kTimeBetweenLogsInSeconds = 5;
|
| - const base::TimeDelta time_since_last_log =
|
| - base::TimeTicks::Now() - last_log_time_;
|
| - if (time_since_last_log.InSeconds() < kTimeBetweenLogsInSeconds)
|
| + const int kNumQueriesIn5Seconds = 5;
|
| + if (num_queries_ < kNumQueriesIn5Seconds) {
|
| return;
|
| + }
|
|
|
| // Calculate how frequent the AEC delay was out of bounds since last time we
|
| - // updated UMA histograms. Then store the result into one of three histogram
|
| - // buckets; see DelayBasedEchoQuality.
|
| - float poor_delay_frequency = 0.f;
|
| - if (echo_total_delay_counts_ > 0) {
|
| - poor_delay_frequency = static_cast<float>(echo_poor_delay_counts_) /
|
| - static_cast<float>(echo_total_delay_counts_);
|
| - UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
|
| - EchoDelayFrequencyToQuality(poor_delay_frequency),
|
| - DELAY_BASED_ECHO_QUALITY_MAX);
|
| - }
|
| - echo_poor_delay_counts_ = 0;
|
| - echo_total_delay_counts_ = 0;
|
| - last_log_time_ = base::TimeTicks::Now();
|
| + // updated UMA histograms by averaging |echo_fraction_poor_delays_| over
|
| + // |num_queries_|. Then store the result into one of four histogram buckets;
|
| + // see DelayBasedEchoQuality.
|
| + float poor_delay_frequency = echo_fraction_poor_delays_ / num_queries_;
|
| + UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
|
| + EchoDelayFrequencyToQuality(poor_delay_frequency),
|
| + DELAY_BASED_ECHO_QUALITY_MAX);
|
| + num_queries_ = 0;
|
| + echo_fraction_poor_delays_ = 0.0f;
|
| }
|
|
|
| void EnableEchoCancellation(AudioProcessing* audio_processing) {
|
| @@ -338,14 +350,14 @@ void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
|
| CHECK_EQ(err, 0);
|
| }
|
|
|
| -void GetAecStats(AudioProcessing* audio_processing,
|
| +void GetAecStats(webrtc::EchoCancellation* echo_cancellation,
|
| webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
|
| // These values can take on valid negative values, so use the lowest possible
|
| // level as default rather than -1.
|
| stats->echo_return_loss = -100;
|
| stats->echo_return_loss_enhancement = -100;
|
|
|
| - // These values can also be negative, but in practice -1 is only used to
|
| + // The median value can also be negative, but in practice -1 is only used to
|
| // signal insufficient data, since the resolution is limited to multiples
|
| // of 4ms.
|
| stats->echo_delay_median_ms = -1;
|
| @@ -354,9 +366,9 @@ void GetAecStats(AudioProcessing* audio_processing,
|
| // TODO(ajm): Re-enable this metric once we have a reliable implementation.
|
| stats->aec_quality_min = -1.0f;
|
|
|
| - if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
|
| - !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
|
| - !audio_processing->echo_cancellation()->is_enabled()) {
|
| + if (!echo_cancellation->are_metrics_enabled() ||
|
| + !echo_cancellation->is_delay_logging_enabled() ||
|
| + !echo_cancellation->is_enabled()) {
|
| return;
|
| }
|
|
|
| @@ -364,14 +376,16 @@ void GetAecStats(AudioProcessing* audio_processing,
|
| // here, but it appears to be unsuitable currently. Revisit after this is
|
| // investigated: http://b/issue?id=5666755
|
| webrtc::EchoCancellation::Metrics echo_metrics;
|
| - if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
|
| + if (!echo_cancellation->GetMetrics(&echo_metrics)) {
|
| stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
|
| stats->echo_return_loss_enhancement =
|
| echo_metrics.echo_return_loss_enhancement.instant;
|
| }
|
|
|
| int median = 0, std = 0;
|
| - if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) {
|
| + float dummy = 0;
|
| + if (echo_cancellation->GetDelayMetrics(&median, &std, &dummy) ==
|
| + webrtc::AudioProcessing::kNoError) {
|
| stats->echo_delay_median_ms = median;
|
| stats->echo_delay_std_ms = std;
|
| }
|
|
|