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/logging.h"
9 #include "base/path_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/common/media/media_stream_options.h"
12 #include "content/renderer/media/rtc_media_constraints.h"
13 #include "media/audio/audio_parameters.h"
14 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
15 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface.h"
16 #include "third_party/webrtc/modules/audio_processing/include/audio_processing.h"
17 #include "third_party/webrtc/modules/audio_processing/typing_detection.h"
23 // Constant constraint keys which enables default audio constraints on
24 // mediastreams with audio.
28 } const kDefaultAudioConstraints[] = {
29 { webrtc::MediaConstraintsInterface::kEchoCancellation,
30 webrtc::MediaConstraintsInterface::kValueTrue },
31 #if defined(OS_CHROMEOS) || defined(OS_MACOSX)
32 // Enable the extended filter mode AEC on platforms with known echo issues.
33 { webrtc::MediaConstraintsInterface::kExperimentalEchoCancellation,
34 webrtc::MediaConstraintsInterface::kValueTrue },
36 { webrtc::MediaConstraintsInterface::kAutoGainControl,
37 webrtc::MediaConstraintsInterface::kValueTrue },
38 { webrtc::MediaConstraintsInterface::kExperimentalAutoGainControl,
39 webrtc::MediaConstraintsInterface::kValueTrue },
40 { webrtc::MediaConstraintsInterface::kNoiseSuppression,
41 webrtc::MediaConstraintsInterface::kValueTrue },
42 { webrtc::MediaConstraintsInterface::kHighpassFilter,
43 webrtc::MediaConstraintsInterface::kValueTrue },
44 { webrtc::MediaConstraintsInterface::kTypingNoiseDetection,
45 webrtc::MediaConstraintsInterface::kValueTrue },
47 { content::kMediaStreamAudioDucking,
48 webrtc::MediaConstraintsInterface::kValueTrue },
54 void ApplyFixedAudioConstraints(RTCMediaConstraints* constraints) {
55 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
56 bool already_set_value;
57 if (!webrtc::FindConstraint(constraints, kDefaultAudioConstraints[i].key,
58 &already_set_value, NULL)) {
59 constraints->AddOptional(kDefaultAudioConstraints[i].key,
60 kDefaultAudioConstraints[i].value, false);
62 DVLOG(1) << "Constraint " << kDefaultAudioConstraints[i].key
63 << " already set to " << already_set_value;
68 bool NeedsAudioProcessing(const blink::WebMediaConstraints& constraints,
70 RTCMediaConstraints native_constraints(constraints);
71 ApplyFixedAudioConstraints(&native_constraints);
72 if (effects & media::AudioParameters::ECHO_CANCELLER) {
73 // If platform echo canceller is enabled, disable the software AEC.
74 native_constraints.AddOptional(
75 MediaConstraintsInterface::kEchoCancellation,
76 MediaConstraintsInterface::kValueFalse, true);
78 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
80 if (webrtc::FindConstraint(&native_constraints,
81 kDefaultAudioConstraints[i].key, &value, NULL) &&
90 bool GetPropertyFromConstraints(const MediaConstraintsInterface* constraints,
91 const std::string& key) {
93 return webrtc::FindConstraint(constraints, key, &value, NULL) && value;
96 void EnableEchoCancellation(AudioProcessing* audio_processing) {
97 #if defined(OS_ANDROID)
98 // Mobile devices are using AECM.
99 int err = audio_processing->echo_control_mobile()->set_routing_mode(
100 webrtc::EchoControlMobile::kSpeakerphone);
101 err |= audio_processing->echo_control_mobile()->Enable(true);
104 int err = audio_processing->echo_cancellation()->set_suppression_level(
105 webrtc::EchoCancellation::kHighSuppression);
107 // Enable the metrics for AEC.
108 err |= audio_processing->echo_cancellation()->enable_metrics(true);
109 err |= audio_processing->echo_cancellation()->enable_delay_logging(true);
110 err |= audio_processing->echo_cancellation()->Enable(true);
115 void EnableNoiseSuppression(AudioProcessing* audio_processing) {
116 int err = audio_processing->noise_suppression()->set_level(
117 webrtc::NoiseSuppression::kHigh);
118 err |= audio_processing->noise_suppression()->Enable(true);
122 void EnableExperimentalNoiseSuppression(AudioProcessing* audio_processing) {
123 CHECK_EQ(audio_processing->EnableExperimentalNs(true), 0);
126 void EnableHighPassFilter(AudioProcessing* audio_processing) {
127 CHECK_EQ(audio_processing->high_pass_filter()->Enable(true), 0);
130 void EnableTypingDetection(AudioProcessing* audio_processing,
131 webrtc::TypingDetection* typing_detector) {
132 int err = audio_processing->voice_detection()->Enable(true);
133 err |= audio_processing->voice_detection()->set_likelihood(
134 webrtc::VoiceDetection::kVeryLowLikelihood);
137 // Configure the update period to 1s (100 * 10ms) in the typing detector.
138 typing_detector->SetParameters(0, 0, 0, 0, 0, 100);
141 void EnableExperimentalEchoCancellation(AudioProcessing* audio_processing) {
142 webrtc::Config config;
143 config.Set<webrtc::DelayCorrection>(new webrtc::DelayCorrection(true));
144 audio_processing->SetExtraOptions(config);
147 void StartEchoCancellationDump(AudioProcessing* audio_processing,
148 const base::PlatformFile& aec_dump_file) {
149 DCHECK_NE(aec_dump_file, base::kInvalidPlatformFileValue);
151 FILE* stream = base::FdopenPlatformFile(aec_dump_file, "w");
153 LOG(ERROR) << "Failed to open AEC dump file";
157 if (audio_processing->StartDebugRecording(stream))
158 DLOG(ERROR) << "Fail to start AEC debug recording";
161 void StopEchoCancellationDump(AudioProcessing* audio_processing) {
162 if (audio_processing->StopDebugRecording())
163 DLOG(ERROR) << "Fail to stop AEC debug recording";
166 void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
167 #if defined(OS_ANDROID) || defined(OS_IOS)
168 const webrtc::GainControl::Mode mode = webrtc::GainControl::kFixedDigital;
170 const webrtc::GainControl::Mode mode = webrtc::GainControl::kAdaptiveAnalog;
172 int err = audio_processing->gain_control()->set_mode(mode);
173 err |= audio_processing->gain_control()->Enable(true);
177 void GetAecStats(AudioProcessing* audio_processing,
178 webrtc::AudioProcessorInterface::AudioProcessorStats* stats) {
179 // These values can take on valid negative values, so use the lowest possible
180 // level as default rather than -1.
181 stats->echo_return_loss = -100;
182 stats->echo_return_loss_enhancement = -100;
184 // These values can also be negative, but in practice -1 is only used to
185 // signal insufficient data, since the resolution is limited to multiples
187 stats->echo_delay_median_ms = -1;
188 stats->echo_delay_std_ms = -1;
190 // TODO(ajm): Re-enable this metric once we have a reliable implementation.
191 stats->aec_quality_min = -1.0f;
193 if (!audio_processing->echo_cancellation()->are_metrics_enabled() ||
194 !audio_processing->echo_cancellation()->is_delay_logging_enabled() ||
195 !audio_processing->echo_cancellation()->is_enabled()) {
199 // TODO(ajm): we may want to use VoECallReport::GetEchoMetricsSummary
200 // here, but it appears to be unsuitable currently. Revisit after this is
201 // investigated: http://b/issue?id=5666755
202 webrtc::EchoCancellation::Metrics echo_metrics;
203 if (!audio_processing->echo_cancellation()->GetMetrics(&echo_metrics)) {
204 stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
205 stats->echo_return_loss_enhancement =
206 echo_metrics.echo_return_loss_enhancement.instant;
209 int median = 0, std = 0;
210 if (!audio_processing->echo_cancellation()->GetDelayMetrics(&median, &std)) {
211 stats->echo_delay_median_ms = median;
212 stats->echo_delay_std_ms = std;
216 } // namespace content