[ServiceWorker] Implement WebServiceWorkerContextClient::openWindow().
[chromium-blink-merge.git] / content / renderer / media / media_stream_audio_processor_options.cc
blobb2465b3350286d05a8f543b8c11bf04455a0bca5
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
3 // found in the LICENSE file.
5 #include "content/renderer/media/media_stream_audio_processor_options.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/logging.h"
10 #include "base/metrics/field_trial.h"
11 #include "base/metrics/histogram.h"
12 #include "base/strings/string_number_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"
16 #include "content/renderer/media/media_stream_constraints_util.h"
17 #include "content/renderer/media/media_stream_source.h"
18 #include "content/renderer/media/rtc_media_constraints.h"
19 #include "media/audio/audio_parameters.h"
20 #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h"
21 #include "third_party/webrtc/modules/audio_processing/typing_detection.h"
23 namespace content {
25 const char MediaAudioConstraints::kEchoCancellation[] = "echoCancellation";
26 const char MediaAudioConstraints::kGoogEchoCancellation[] =
27 "googEchoCancellation";
28 const char MediaAudioConstraints::kGoogExperimentalEchoCancellation[] =
29 "googEchoCancellation2";
30 const char MediaAudioConstraints::kGoogAutoGainControl[] =
31 "googAutoGainControl";
32 const char MediaAudioConstraints::kGoogExperimentalAutoGainControl[] =
33 "googAutoGainControl2";
34 const char MediaAudioConstraints::kGoogNoiseSuppression[] =
35 "googNoiseSuppression";
36 const char MediaAudioConstraints::kGoogExperimentalNoiseSuppression[] =
37 "googNoiseSuppression2";
38 const char MediaAudioConstraints::kGoogBeamforming[] = "googBeamforming";
39 const char MediaAudioConstraints::kGoogHighpassFilter[] = "googHighpassFilter";
40 const char MediaAudioConstraints::kGoogTypingNoiseDetection[] =
41 "googTypingNoiseDetection";
42 const char MediaAudioConstraints::kGoogAudioMirroring[] = "googAudioMirroring";
44 namespace {
46 // Constant constraint keys which enables default audio constraints on
47 // mediastreams with audio.
48 struct {
49 const char* key;
50 bool value;
51 } const kDefaultAudioConstraints[] = {
52 { MediaAudioConstraints::kEchoCancellation, true },
53 { MediaAudioConstraints::kGoogEchoCancellation, true },
54 #if defined(OS_ANDROID) || defined(OS_IOS)
55 { MediaAudioConstraints::kGoogExperimentalEchoCancellation, false },
56 #else
57 // Enable the extended filter mode AEC on all non-mobile platforms.
58 { MediaAudioConstraints::kGoogExperimentalEchoCancellation, true },
59 #endif
60 { MediaAudioConstraints::kGoogAutoGainControl, true },
61 { MediaAudioConstraints::kGoogExperimentalAutoGainControl, true },
62 { MediaAudioConstraints::kGoogNoiseSuppression, true },
63 { MediaAudioConstraints::kGoogHighpassFilter, true },
64 { MediaAudioConstraints::kGoogTypingNoiseDetection, true },
65 { MediaAudioConstraints::kGoogExperimentalNoiseSuppression, false },
66 { MediaAudioConstraints::kGoogBeamforming, false },
67 #if defined(OS_WIN)
68 { kMediaStreamAudioDucking, true },
69 #else
70 { kMediaStreamAudioDucking, false },
71 #endif
72 { kMediaStreamAudioHotword, false },
75 bool IsAudioProcessingConstraint(const std::string& key) {
76 // |kMediaStreamAudioDucking| does not require audio processing.
77 return key != kMediaStreamAudioDucking;
80 // Used to log echo quality based on delay estimates.
81 enum DelayBasedEchoQuality {
82 DELAY_BASED_ECHO_QUALITY_GOOD = 0,
83 DELAY_BASED_ECHO_QUALITY_SPURIOUS,
84 DELAY_BASED_ECHO_QUALITY_BAD,
85 DELAY_BASED_ECHO_QUALITY_MAX
88 DelayBasedEchoQuality EchoDelayFrequencyToQuality(float delay_frequency) {
89 const float kEchoDelayFrequencyLowerLimit = 0.1f;
90 const float kEchoDelayFrequencyUpperLimit = 0.8f;
91 // DELAY_BASED_ECHO_QUALITY_GOOD
92 // delay is out of bounds during at most 10 % of the time.
93 // DELAY_BASED_ECHO_QUALITY_SPURIOUS
94 // delay is out of bounds 10-80 % of the time.
95 // DELAY_BASED_ECHO_QUALITY_BAD
96 // delay is mostly out of bounds >= 80 % of the time.
97 if (delay_frequency <= kEchoDelayFrequencyLowerLimit)
98 return DELAY_BASED_ECHO_QUALITY_GOOD;
99 else if (delay_frequency < kEchoDelayFrequencyUpperLimit)
100 return DELAY_BASED_ECHO_QUALITY_SPURIOUS;
101 else
102 return DELAY_BASED_ECHO_QUALITY_BAD;
105 } // namespace
107 // TODO(xians): Remove this method after the APM in WebRtc is deprecated.
108 void MediaAudioConstraints::ApplyFixedAudioConstraints(
109 RTCMediaConstraints* constraints) {
110 for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
111 bool already_set_value;
112 if (!webrtc::FindConstraint(constraints, kDefaultAudioConstraints[i].key,
113 &already_set_value, NULL)) {
114 const std::string value = kDefaultAudioConstraints[i].value ?
115 webrtc::MediaConstraintsInterface::kValueTrue :
116 webrtc::MediaConstraintsInterface::kValueFalse;
117 constraints->AddOptional(kDefaultAudioConstraints[i].key, value, false);
118 } else {
119 DVLOG(1) << "Constraint " << kDefaultAudioConstraints[i].key
120 << " already set to " << already_set_value;
125 MediaAudioConstraints::MediaAudioConstraints(
126 const blink::WebMediaConstraints& constraints, int effects)
127 : constraints_(constraints),
128 effects_(effects),
129 default_audio_processing_constraint_value_(true) {
130 // The default audio processing constraints are turned off when
131 // - gUM has a specific kMediaStreamSource, which is used by tab capture
132 // and screen capture.
133 // - |kEchoCancellation| is explicitly set to false.
134 std::string value_str;
135 bool value_bool = false;
136 if ((GetConstraintValueAsString(constraints, kMediaStreamSource,
137 &value_str)) ||
138 (GetConstraintValueAsBoolean(constraints_, kEchoCancellation,
139 &value_bool) && !value_bool)) {
140 default_audio_processing_constraint_value_ = false;
144 MediaAudioConstraints::~MediaAudioConstraints() {}
146 bool MediaAudioConstraints::GetProperty(const std::string& key) {
147 // Return the value if the constraint is specified in |constraints|,
148 // otherwise return the default value.
149 bool value = false;
150 if (!GetConstraintValueAsBoolean(constraints_, key, &value))
151 value = GetDefaultValueForConstraint(constraints_, key);
153 return value;
156 bool MediaAudioConstraints::GetEchoCancellationProperty() {
157 // If platform echo canceller is enabled, disable the software AEC.
158 if (effects_ & media::AudioParameters::ECHO_CANCELLER)
159 return false;
161 // If |kEchoCancellation| is specified in the constraints, it will
162 // override the value of |kGoogEchoCancellation|.
163 bool value = false;
164 if (GetConstraintValueAsBoolean(constraints_, kEchoCancellation, &value))
165 return value;
167 return GetProperty(kGoogEchoCancellation);
170 bool MediaAudioConstraints::IsValid() {
171 blink::WebVector<blink::WebMediaConstraint> mandatory;
172 constraints_.getMandatoryConstraints(mandatory);
173 for (size_t i = 0; i < mandatory.size(); ++i) {
174 const std::string key = mandatory[i].m_name.utf8();
175 if (key == kMediaStreamSource || key == kMediaStreamSourceId ||
176 key == MediaStreamSource::kSourceId) {
177 // Ignore Chrome specific Tab capture and |kSourceId| constraints.
178 continue;
181 bool valid = false;
182 for (size_t j = 0; j < arraysize(kDefaultAudioConstraints); ++j) {
183 if (key == kDefaultAudioConstraints[j].key) {
184 bool value = false;
185 valid = GetMandatoryConstraintValueAsBoolean(constraints_, key, &value);
186 break;
190 if (!valid) {
191 DLOG(ERROR) << "Invalid MediaStream constraint. Name: " << key;
192 return false;
196 return true;
199 bool MediaAudioConstraints::GetDefaultValueForConstraint(
200 const blink::WebMediaConstraints& constraints, const std::string& key) {
201 // |kMediaStreamAudioDucking| is not restricted by
202 // |default_audio_processing_constraint_value_| since it does not require
203 // audio processing.
204 if (!default_audio_processing_constraint_value_ &&
205 IsAudioProcessingConstraint(key))
206 return false;
208 for (size_t i = 0; i < arraysize(kDefaultAudioConstraints); ++i) {
209 if (kDefaultAudioConstraints[i].key == key)
210 return kDefaultAudioConstraints[i].value;
213 return false;
216 EchoInformation::EchoInformation()
217 : echo_poor_delay_counts_(0),
218 echo_total_delay_counts_(0),
219 last_log_time_(base::TimeTicks::Now()) {}
221 EchoInformation::~EchoInformation() {}
223 void EchoInformation::UpdateAecDelayStats(int delay) {
224 // One way to get an indication of how well the echo cancellation performs is
225 // to compare the, by AEC, estimated delay with the AEC filter length.
226 // |kMaxAecFilterLengthMs| is the maximum delay we can allow before we
227 // consider the AEC to fail. This value should not be larger than the filter
228 // length used inside AEC. This is for now set to match the extended filter
229 // mode which is turned on for all platforms.
230 const int kMaxAecFilterLengthMs = 128;
231 if ((delay < -2) || (delay > kMaxAecFilterLengthMs)) {
232 // The |delay| is out of bounds which indicates that the echo cancellation
233 // filter can not handle the echo. Hence, we have a potential full echo
234 // case. |delay| values {-1, -2} are reserved for errors.
235 ++echo_poor_delay_counts_;
237 ++echo_total_delay_counts_;
238 LogAecDelayStats();
241 void EchoInformation::LogAecDelayStats() {
242 // We update the UMA statistics every 5 seconds.
243 const int kTimeBetweenLogsInSeconds = 5;
244 const base::TimeDelta time_since_last_log =
245 base::TimeTicks::Now() - last_log_time_;
246 if (time_since_last_log.InSeconds() < kTimeBetweenLogsInSeconds)
247 return;
249 // 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
251 // buckets; see DelayBasedEchoQuality.
252 float poor_delay_frequency = 0.f;
253 if (echo_total_delay_counts_ > 0) {
254 poor_delay_frequency = static_cast<float>(echo_poor_delay_counts_) /
255 static_cast<float>(echo_total_delay_counts_);
256 UMA_HISTOGRAM_ENUMERATION("WebRTC.AecDelayBasedQuality",
257 EchoDelayFrequencyToQuality(poor_delay_frequency),
258 DELAY_BASED_ECHO_QUALITY_MAX);
260 echo_poor_delay_counts_ = 0;
261 echo_total_delay_counts_ = 0;
262 last_log_time_ = base::TimeTicks::Now();
265 void EnableEchoCancellation(AudioProcessing* audio_processing) {
266 #if defined(OS_ANDROID) || defined(OS_IOS)
267 const std::string group_name =
268 base::FieldTrialList::FindFullName("ReplaceAECMWithAEC");
269 if (group_name.empty() ||
270 !(group_name == "Enabled" || group_name == "DefaultEnabled")) {
271 // Mobile devices are using AECM.
272 int err = audio_processing->echo_control_mobile()->set_routing_mode(
273 webrtc::EchoControlMobile::kSpeakerphone);
274 err |= audio_processing->echo_control_mobile()->Enable(true);
275 CHECK_EQ(err, 0);
276 return;
278 #endif
279 int err = audio_processing->echo_cancellation()->set_suppression_level(
280 webrtc::EchoCancellation::kHighSuppression);
282 // Enable the metrics for AEC.
283 err |= audio_processing->echo_cancellation()->enable_metrics(true);
284 err |= audio_processing->echo_cancellation()->enable_delay_logging(true);
285 err |= audio_processing->echo_cancellation()->Enable(true);
286 CHECK_EQ(err, 0);
289 void EnableNoiseSuppression(AudioProcessing* audio_processing) {
290 int err = audio_processing->noise_suppression()->set_level(
291 webrtc::NoiseSuppression::kHigh);
292 err |= audio_processing->noise_suppression()->Enable(true);
293 CHECK_EQ(err, 0);
296 void EnableHighPassFilter(AudioProcessing* audio_processing) {
297 CHECK_EQ(audio_processing->high_pass_filter()->Enable(true), 0);
300 void EnableTypingDetection(AudioProcessing* audio_processing,
301 webrtc::TypingDetection* typing_detector) {
302 int err = audio_processing->voice_detection()->Enable(true);
303 err |= audio_processing->voice_detection()->set_likelihood(
304 webrtc::VoiceDetection::kVeryLowLikelihood);
305 CHECK_EQ(err, 0);
307 // Configure the update period to 1s (100 * 10ms) in the typing detector.
308 typing_detector->SetParameters(0, 0, 0, 0, 0, 100);
311 void StartEchoCancellationDump(AudioProcessing* audio_processing,
312 base::File aec_dump_file) {
313 DCHECK(aec_dump_file.IsValid());
315 FILE* stream = base::FileToFILE(aec_dump_file.Pass(), "w");
316 if (!stream) {
317 LOG(ERROR) << "Failed to open AEC dump file";
318 return;
321 if (audio_processing->StartDebugRecording(stream))
322 DLOG(ERROR) << "Fail to start AEC debug recording";
325 void StopEchoCancellationDump(AudioProcessing* audio_processing) {
326 if (audio_processing->StopDebugRecording())
327 DLOG(ERROR) << "Fail to stop AEC debug recording";
330 void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
331 #if defined(OS_ANDROID) || defined(OS_IOS)
332 const webrtc::GainControl::Mode mode = webrtc::GainControl::kFixedDigital;
333 #else
334 const webrtc::GainControl::Mode mode = webrtc::GainControl::kAdaptiveAnalog;
335 #endif
336 int err = audio_processing->gain_control()->set_mode(mode);
337 err |= audio_processing->gain_control()->Enable(true);
338 CHECK_EQ(err, 0);
341 void GetAecStats(AudioProcessing* audio_processing,
342 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
343 // These values can take on valid negative values, so use the lowest possible
344 // level as default rather than -1.
345 stats->echo_return_loss = -100;
346 stats->echo_return_loss_enhancement = -100;
348 // These values can also be negative, but in practice -1 is only used to
349 // signal insufficient data, since the resolution is limited to multiples
350 // of 4ms.
351 stats->echo_delay_median_ms = -1;
352 stats->echo_delay_std_ms = -1;
354 // TODO(ajm): Re-enable this metric once we have a reliable implementation.
355 stats->aec_quality_min = -1.0f;
357 if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
358 !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
359 !audio_processing->echo_cancellation()->is_enabled()) {
360 return;
363 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
364 // here, but it appears to be unsuitable currently. Revisit after this is
365 // investigated: http://b/issue?id=5666755
366 webrtc::EchoCancellation::Metrics echo_metrics;
367 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
368 stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
369 stats->echo_return_loss_enhancement =
370 echo_metrics.echo_return_loss_enhancement.instant;
373 int median = 0, std = 0;
374 if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) {
375 stats->echo_delay_median_ms = median;
376 stats->echo_delay_std_ms = std;
380 } // namespace content