320d1a6ba31d8296160a2a67b1c07523aa4d12ef
[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/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"
18
19 namespace content {
20
21 namespace {
22
23 // Constant constraint keys which enables default audio constraints on
24 // mediastreams with audio.
25 struct {
26   const char* key;
27   const char* value;
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 },
35 #endif
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 },
46 #if defined(OS_WIN)
47   { content::kMediaStreamAudioDucking,
48     webrtc::MediaConstraintsInterface::kValueTrue },
49 #endif
50 };
51
52 } // namespace
53
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);
61     } else {
62       DVLOG(1) << "Constraint " << kDefaultAudioConstraints[i].key
63                << " already set to " << already_set_value;
64     }
65   }
66 }
67
68 bool NeedsAudioProcessing(const blink::WebMediaConstraints& constraints,
69                           int effects) {
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);
77   }
78   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kDefaultAudioConstraints); ++i) {
79     bool value = false;
80     if (webrtc::FindConstraint(&native_constraints,
81                                kDefaultAudioConstraints[i].key, &value, NULL) &&
82         value) {
83       return true;
84     }
85   }
86
87   return false;
88 }
89
90 bool GetPropertyFromConstraints(const MediaConstraintsInterface* constraints,
91                                 const std::string& key) {
92   bool value = false;
93   return webrtc::FindConstraint(constraints, key, &value, NULL) && value;
94 }
95
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);
102   CHECK_EQ(err, 0);
103 #else
104   int err = audio_processing->echo_cancellation()->set_suppression_level(
105       webrtc::EchoCancellation::kHighSuppression);
106
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);
111   CHECK_EQ(err, 0);
112 #endif
113 }
114
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);
119   CHECK_EQ(err, 0);
120 }
121
122 void EnableExperimentalNoiseSuppression(AudioProcessing* audio_processing) {
123   CHECK_EQ(audio_processing->EnableExperimentalNs(true), 0);
124 }
125
126 void EnableHighPassFilter(AudioProcessing* audio_processing) {
127   CHECK_EQ(audio_processing->high_pass_filter()->Enable(true), 0);
128 }
129
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);
135   CHECK_EQ(err, 0);
136
137   // Configure the update period to 1s (100 * 10ms) in the typing detector.
138   typing_detector->SetParameters(0, 0, 0, 0, 0, 100);
139 }
140
141 void EnableExperimentalEchoCancellation(AudioProcessing* audio_processing) {
142   webrtc::Config config;
143   config.Set<webrtc::DelayCorrection>(new webrtc::DelayCorrection(true));
144   audio_processing->SetExtraOptions(config);
145 }
146
147 void StartEchoCancellationDump(AudioProcessing* audio_processing,
148                                const base::PlatformFile& aec_dump_file) {
149   DCHECK_NE(aec_dump_file, base::kInvalidPlatformFileValue);
150
151   FILE* stream = base::FdopenPlatformFile(aec_dump_file, "w");
152   if (!stream) {
153     LOG(ERROR) << "Failed to open AEC dump file";
154     return;
155   }
156
157   if (audio_processing->StartDebugRecording(stream))
158     DLOG(ERROR) << "Fail to start AEC debug recording";
159 }
160
161 void StopEchoCancellationDump(AudioProcessing* audio_processing) {
162   if (audio_processing->StopDebugRecording())
163     DLOG(ERROR) << "Fail to stop AEC debug recording";
164 }
165
166 void EnableAutomaticGainControl(AudioProcessing* audio_processing) {
167 #if defined(OS_ANDROID) || defined(OS_IOS)
168   const webrtc::GainControl::Mode mode = webrtc::GainControl::kFixedDigital;
169 #else
170   const webrtc::GainControl::Mode mode = webrtc::GainControl::kAdaptiveAnalog;
171 #endif
172   int err = audio_processing->gain_control()->set_mode(mode);
173   err |= audio_processing->gain_control()->Enable(true);
174   CHECK_EQ(err, 0);
175 }
176
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;
183
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
186   // of 4ms.
187   stats->echo_delay_median_ms = -1;
188   stats->echo_delay_std_ms = -1;
189
190   // TODO(ajm): Re-enable this metric once we have a reliable implementation.
191   stats->aec_quality_min = -1.0f;
192
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()) {
196     return;
197   }
198
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;
207   }
208
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;
213   }
214 }
215
216 }  // namespace content