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