Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / renderer / media / media_stream_audio_processor_options.cc
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.
4
5 #include "content/renderer/media/media_stream_audio_processor_options.h"
6
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"
19
20 namespace content {
21
22 namespace {
23
24 // Constant constraint keys which enables default audio constraints on
25 // mediastreams with audio.
26 struct {
27   const char* key;
28   const char* value;
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 },
36 #endif
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 },
47 #if defined(OS_WIN)
48   { content::kMediaStreamAudioDucking,
49     webrtc::MediaConstraintsInterface::kValueTrue },
50 #endif
51 };
52
53 } // namespace
54
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);
62     } else {
63       DVLOG(1) << "Constraint " << kDefaultAudioConstraints[i].key
64                << " already set to " << already_set_value;
65     }
66   }
67 }
68
69 bool NeedsAudioProcessing(const blink::WebMediaConstraints& constraints,
70                           int effects) {
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);
78   }
79   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
80     bool value = false;
81     if (webrtc::FindConstraint(&native_constraints,
82                                kDefaultAudioConstraints[i].key, &value, NULL) &&
83         value) {
84       return true;
85     }
86   }
87
88   return false;
89 }
90
91 bool GetPropertyFromConstraints(const MediaConstraintsInterface* constraints,
92                                 const std::string& key) {
93   bool value = false;
94   return webrtc::FindConstraint(constraints, key, &value, NULL) && value;
95 }
96
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);
106     CHECK_EQ(err, 0);
107     return;
108   }
109 #endif
110   int err = audio_processing->echo_cancellation()->set_suppression_level(
111       webrtc::EchoCancellation::kHighSuppression);
112
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);
117   CHECK_EQ(err, 0);
118 }
119
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);
124   CHECK_EQ(err, 0);
125 }
126
127 void EnableExperimentalNoiseSuppression(AudioProcessing* audio_processing) {
128   CHECK_EQ(audio_processing->EnableExperimentalNs(true), 0);
129 }
130
131 void EnableHighPassFilter(AudioProcessing* audio_processing) {
132   CHECK_EQ(audio_processing->high_pass_filter()->Enable(true), 0);
133 }
134
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);
140   CHECK_EQ(err, 0);
141
142   // Configure the update period to 1s (100 * 10ms) in the typing detector.
143   typing_detector->SetParameters(0, 0, 0, 0, 0, 100);
144 }
145
146 void EnableExperimentalEchoCancellation(AudioProcessing* audio_processing) {
147   webrtc::Config config;
148   config.Set<webrtc::DelayCorrection>(new webrtc::DelayCorrection(true));
149   audio_processing->SetExtraOptions(config);
150 }
151
152 void StartEchoCancellationDump(AudioProcessing* audio_processing,
153                                const base::PlatformFile& aec_dump_file) {
154   DCHECK_NE(aec_dump_file, base::kInvalidPlatformFileValue);
155
156   FILE* stream = base::FdopenPlatformFile(aec_dump_file, "w");
157   if (!stream) {
158     LOG(ERROR) << "Failed to open AEC dump file";
159     return;
160   }
161
162   if (audio_processing->StartDebugRecording(stream))
163     DLOG(ERROR) << "Fail to start AEC debug recording";
164 }
165
166 void StopEchoCancellationDump(AudioProcessing* audio_processing) {
167   if (audio_processing->StopDebugRecording())
168     DLOG(ERROR) << "Fail to stop AEC debug recording";
169 }
170
171 void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
172 #if defined(OS_ANDROID) || defined(OS_IOS)
173   const webrtc::GainControl::Mode mode = webrtc::GainControl::kFixedDigital;
174 #else
175   const webrtc::GainControl::Mode mode = webrtc::GainControl::kAdaptiveAnalog;
176 #endif
177   int err = audio_processing->gain_control()->set_mode(mode);
178   err |= audio_processing->gain_control()->Enable(true);
179   CHECK_EQ(err, 0);
180 }
181
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;
188
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
191   // of 4ms.
192   stats->echo_delay_median_ms = -1;
193   stats->echo_delay_std_ms = -1;
194
195   // TODO(ajm): Re-enable this metric once we have a reliable implementation.
196   stats->aec_quality_min = -1.0f;
197
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()) {
201     return;
202   }
203
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;
212   }
213
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;
218   }
219 }
220
221 }  // namespace content