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..c52471fc4a8ca04cf1d0c54e13977dd06236ec06 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" |
@@ -79,7 +78,8 @@ bool IsAudioProcessingConstraint(const std::string& key) { |
// Used to log echo quality based on delay estimates. |
enum DelayBasedEchoQuality { |
- DELAY_BASED_ECHO_QUALITY_GOOD = 0, |
+ DELAY_BASED_ECHO_QUALITY_INVALID = 0, |
+ DELAY_BASED_ECHO_QUALITY_GOOD, |
DELAY_BASED_ECHO_QUALITY_SPURIOUS, |
DELAY_BASED_ECHO_QUALITY_BAD, |
DELAY_BASED_ECHO_QUALITY_MAX |
@@ -88,13 +88,17 @@ enum DelayBasedEchoQuality { |
DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) { |
const float kEchoDelayFrequencyLowerLimit = 0.1f; |
const float kEchoDelayFrequencyUpperLimit = 0.8f; |
+ // DELAY_BASED_ECHO_QUALITY_INVALID |
+ // delay_frequency is negative which happens if we have insufficient data. |
// DELAY_BASED_ECHO_QUALITY_GOOD |
// delay is out of bounds during at most 10 % of the time. |
// DELAY_BASED_ECHO_QUALITY_SPURIOUS |
// 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) |
+ 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,58 @@ 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(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
|
+ // 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.
|
+ // We use one of them, |fraction_poor_delays|, but aggregate over 5 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 5 such queries. |
+ // WebRTC process audio in 10 ms chunks. |
+ const int kNumChunksInOneSecond = 100; |
+ if (!audio_processing->echo_cancellation()->is_delay_logging_enabled() || |
+ !audio_processing->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 (!audio_processing->echo_cancellation()->GetDelayMetrics( |
+ &dummy_median, &dummy_std, &fraction_poor_delays)) { |
+ 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) { |
@@ -345,7 +355,7 @@ void GetAecStats(AudioProcessing* audio_processing, |
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; |
@@ -371,7 +381,9 @@ void GetAecStats(AudioProcessing* audio_processing, |
} |
int median = 0, std = 0; |
- if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) { |
+ float dummy = 0; |
+ if (!audio_processing->echo_cancellation()->GetDelayMetrics( |
+ &median, &std, &dummy)) { |
stats->echo_delay_median_ms = median; |
stats->echo_delay_std_ms = std; |
} |