Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: content/renderer/media/media_stream_audio_processor.cc

Issue 227743004: Added a kEchoCancellation constraint to turn off the audio processing. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: moved some of the constraints code to MediaAudioConstraints class, and hope it makes the code more … Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/media_stream_audio_processor.h" 5 #include "content/renderer/media/media_stream_audio_processor.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/metrics/field_trial.h" 9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "content/public/common/content_switches.h" 11 #include "content/public/common/content_switches.h"
12 #include "content/renderer/media/media_stream_audio_processor_options.h" 12 #include "content/renderer/media/media_stream_audio_processor_options.h"
13 #include "content/renderer/media/rtc_media_constraints.h" 13 #include "content/renderer/media/rtc_media_constraints.h"
14 #include "media/audio/audio_parameters.h" 14 #include "media/audio/audio_parameters.h"
15 #include "media/base/audio_converter.h" 15 #include "media/base/audio_converter.h"
16 #include "media/base/audio_fifo.h" 16 #include "media/base/audio_fifo.h"
17 #include "media/base/channel_layout.h" 17 #include "media/base/channel_layout.h"
18 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" 18 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
19 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface .h" 19 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface .h"
20 #include "third_party/webrtc/modules/audio_processing/typing_detection.h" 20 #include "third_party/webrtc/modules/audio_processing/typing_detection.h"
21 21
22 namespace content { 22 namespace content {
23 23
24 namespace { 24 namespace {
25 25
26 using webrtc::AudioProcessing; 26 using webrtc::AudioProcessing;
27 using webrtc::MediaConstraintsInterface;
28 27
29 #if defined(OS_ANDROID) 28 #if defined(OS_ANDROID)
30 const int kAudioProcessingSampleRate = 16000; 29 const int kAudioProcessingSampleRate = 16000;
31 #else 30 #else
32 const int kAudioProcessingSampleRate = 32000; 31 const int kAudioProcessingSampleRate = 32000;
33 #endif 32 #endif
34 const int kAudioProcessingNumberOfChannels = 1; 33 const int kAudioProcessingNumberOfChannels = 1;
35 34
36 const int kMaxNumberOfBuffersInFifo = 2; 35 const int kMaxNumberOfBuffersInFifo = 2;
37 36
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
150 // TODO(xians): consider using SincResampler to save some memcpy. 149 // TODO(xians): consider using SincResampler to save some memcpy.
151 // Handles mixing and resampling between input and output parameters. 150 // Handles mixing and resampling between input and output parameters.
152 media::AudioConverter audio_converter_; 151 media::AudioConverter audio_converter_;
153 scoped_ptr<media::AudioBus> audio_wrapper_; 152 scoped_ptr<media::AudioBus> audio_wrapper_;
154 scoped_ptr<media::AudioFifo> fifo_; 153 scoped_ptr<media::AudioFifo> fifo_;
155 }; 154 };
156 155
157 MediaStreamAudioProcessor::MediaStreamAudioProcessor( 156 MediaStreamAudioProcessor::MediaStreamAudioProcessor(
158 const blink::WebMediaConstraints& constraints, 157 const blink::WebMediaConstraints& constraints,
159 int effects, 158 int effects,
160 MediaStreamType type,
161 WebRtcPlayoutDataSource* playout_data_source) 159 WebRtcPlayoutDataSource* playout_data_source)
162 : render_delay_ms_(0), 160 : render_delay_ms_(0),
163 playout_data_source_(playout_data_source), 161 playout_data_source_(playout_data_source),
164 audio_mirroring_(false), 162 goog_audio_mirroring_(false),
165 typing_detected_(false) { 163 goog_typing_detected_(false) {
166 capture_thread_checker_.DetachFromThread(); 164 capture_thread_checker_.DetachFromThread();
167 render_thread_checker_.DetachFromThread(); 165 render_thread_checker_.DetachFromThread();
168 InitializeAudioProcessingModule(constraints, effects, type); 166 InitializeAudioProcessingModule(constraints, effects);
169 } 167 }
170 168
171 MediaStreamAudioProcessor::~MediaStreamAudioProcessor() { 169 MediaStreamAudioProcessor::~MediaStreamAudioProcessor() {
172 DCHECK(main_thread_checker_.CalledOnValidThread()); 170 DCHECK(main_thread_checker_.CalledOnValidThread());
173 StopAudioProcessing(); 171 StopAudioProcessing();
174 } 172 }
175 173
176 void MediaStreamAudioProcessor::OnCaptureFormatChanged( 174 void MediaStreamAudioProcessor::OnCaptureFormatChanged(
177 const media::AudioParameters& source_params) { 175 const media::AudioParameters& source_params) {
178 DCHECK(main_thread_checker_.CalledOnValidThread()); 176 DCHECK(main_thread_checker_.CalledOnValidThread());
179 // There is no need to hold a lock here since the caller guarantees that 177 // There is no need to hold a lock here since the caller guarantees that
180 // there is no more PushCaptureData() and ProcessAndConsumeData() callbacks 178 // there is no more PushCaptureData() and ProcessAndConsumeData() callbacks
181 // on the capture thread. 179 // on the capture thread.
182 InitializeCaptureConverter(source_params); 180 InitializeCaptureConverter(source_params);
183 181
184 // Reset the |capture_thread_checker_| since the capture data will come from 182 // Reset the |capture_thread_checker_| since the capture data will come from
185 // a new capture thread. 183 // a new capture thread.
186 capture_thread_checker_.DetachFromThread(); 184 capture_thread_checker_.DetachFromThread();
187 } 185 }
188 186
189 void MediaStreamAudioProcessor::PushCaptureData(media::AudioBus* audio_source) { 187 void MediaStreamAudioProcessor::PushCaptureData(media::AudioBus* audio_source) {
190 DCHECK(capture_thread_checker_.CalledOnValidThread()); 188 DCHECK(capture_thread_checker_.CalledOnValidThread());
191 DCHECK_EQ(audio_source->channels(), 189 DCHECK_EQ(audio_source->channels(),
192 capture_converter_->source_parameters().channels()); 190 capture_converter_->source_parameters().channels());
193 DCHECK_EQ(audio_source->frames(), 191 DCHECK_EQ(audio_source->frames(),
194 capture_converter_->source_parameters().frames_per_buffer()); 192 capture_converter_->source_parameters().frames_per_buffer());
195 193
196 if (audio_mirroring_ && 194 if (goog_audio_mirroring_ &&
197 capture_converter_->source_parameters().channel_layout() == 195 capture_converter_->source_parameters().channel_layout() ==
198 media::CHANNEL_LAYOUT_STEREO) { 196 media::CHANNEL_LAYOUT_STEREO) {
199 // Swap the first and second channels. 197 // Swap the first and second channels.
200 audio_source->SwapChannels(0, 1); 198 audio_source->SwapChannels(0, 1);
201 } 199 }
202 200
203 capture_converter_->Push(audio_source); 201 capture_converter_->Push(audio_source);
204 } 202 }
205 203
206 bool MediaStreamAudioProcessor::ProcessAndConsumeData( 204 bool MediaStreamAudioProcessor::ProcessAndConsumeData(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 void MediaStreamAudioProcessor::OnPlayoutDataSourceChanged() { 262 void MediaStreamAudioProcessor::OnPlayoutDataSourceChanged() {
265 DCHECK(main_thread_checker_.CalledOnValidThread()); 263 DCHECK(main_thread_checker_.CalledOnValidThread());
266 // There is no need to hold a lock here since the caller guarantees that 264 // There is no need to hold a lock here since the caller guarantees that
267 // there is no more OnPlayoutData() callback on the render thread. 265 // there is no more OnPlayoutData() callback on the render thread.
268 render_thread_checker_.DetachFromThread(); 266 render_thread_checker_.DetachFromThread();
269 render_converter_.reset(); 267 render_converter_.reset();
270 } 268 }
271 269
272 void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) { 270 void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) {
273 stats->typing_noise_detected = 271 stats->typing_noise_detected =
274 (base::subtle::Acquire_Load(&typing_detected_) != false); 272 (base::subtle::Acquire_Load(&goog_typing_detected_) != false);
275 GetAecStats(audio_processing_.get(), stats); 273 GetAecStats(audio_processing_.get(), stats);
276 } 274 }
277 275
278 void MediaStreamAudioProcessor::InitializeAudioProcessingModule( 276 void MediaStreamAudioProcessor::InitializeAudioProcessingModule(
279 const blink::WebMediaConstraints& constraints, int effects, 277 const blink::WebMediaConstraints& constraints, int effects) {
280 MediaStreamType type) {
281 DCHECK(!audio_processing_); 278 DCHECK(!audio_processing_);
282 279
283 RTCMediaConstraints native_constraints(constraints); 280 MediaAudioConstraints audio_constraints(constraints, effects);
281 DCHECK(audio_constraints.IsValid());
perkj_chrome 2014/04/14 12:15:19 I don't think you should crash if a user user inse
no longer working on chromium 2014/04/14 14:40:50 I was thinking WebRtcAudioCapture::Initialize() wi
284 282
285 // Audio mirroring can be enabled even though audio processing is otherwise 283 // Audio mirroring can be enabled even though audio processing is otherwise
286 // disabled. 284 // disabled.
287 audio_mirroring_ = GetPropertyFromConstraints( 285 goog_audio_mirroring_ = audio_constraints.GetProperty(
288 &native_constraints, webrtc::MediaConstraintsInterface::kAudioMirroring); 286 MediaAudioConstraints::kGoogAudioMirroring);
289 287
290 if (!IsAudioTrackProcessingEnabled()) { 288 if (!IsAudioTrackProcessingEnabled()) {
291 RecordProcessingState(AUDIO_PROCESSING_IN_WEBRTC); 289 RecordProcessingState(AUDIO_PROCESSING_IN_WEBRTC);
292 return; 290 return;
293 } 291 }
294 292
295 // Only apply the fixed constraints for gUM of MEDIA_DEVICE_AUDIO_CAPTURE. 293 // |kEchoCancellation| is used as a master control on enabling/disabling
296 DCHECK(IsAudioMediaType(type)); 294 // the audio processing.
297 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) 295 const bool echo_cancellation = audio_constraints.GetProperty(
298 ApplyFixedAudioConstraints(&native_constraints); 296 MediaAudioConstraints::kEchoCancellation);
299 297 if (!echo_cancellation) {
300 if (effects & media::AudioParameters::ECHO_CANCELLER) { 298 RecordProcessingState(AUDIO_PROCESSING_DISABLED);
301 // If platform echo canceller is enabled, disable the software AEC. 299 return;
302 native_constraints.AddMandatory(
303 MediaConstraintsInterface::kEchoCancellation,
304 MediaConstraintsInterface::kValueFalse, true);
305 } 300 }
306 301
307 #if defined(OS_IOS) 302 #if defined(OS_IOS)
308 // On iOS, VPIO provides built-in AEC and AGC. 303 // On iOS, VPIO provides built-in AEC and AGC.
309 const bool enable_aec = false; 304 const bool goog_aec = false;
310 const bool enable_agc = false; 305 const bool goog_agc = false;
311 #else 306 #else
312 const bool enable_aec = GetPropertyFromConstraints( 307 // TODO(xians): goog_aec should be just echo_cancellation.
313 &native_constraints, MediaConstraintsInterface::kEchoCancellation); 308 const bool goog_aec = audio_constraints.GetProperty(
314 const bool enable_agc = GetPropertyFromConstraints( 309 MediaAudioConstraints::kGoogEchoCancellation);
315 &native_constraints, webrtc::MediaConstraintsInterface::kAutoGainControl); 310 const bool goog_agc = audio_constraints.GetProperty(
311 MediaAudioConstraints::kGoogAutoGainControl);
316 #endif 312 #endif
317 313
318 #if defined(OS_IOS) || defined(OS_ANDROID) 314 #if defined(OS_IOS) || defined(OS_ANDROID)
319 const bool enable_experimental_aec = false; 315 const bool goog_experimental_aec = false;
320 const bool enable_typing_detection = false; 316 const bool goog_typing_detection = false;
321 #else 317 #else
322 const bool enable_experimental_aec = GetPropertyFromConstraints( 318 const bool goog_experimental_aec = audio_constraints.GetProperty(
323 &native_constraints, 319 MediaAudioConstraints::kGoogExperimentalEchoCancellation);
324 MediaConstraintsInterface::kExperimentalEchoCancellation); 320 const bool goog_typing_detection = audio_constraints.GetProperty(
325 const bool enable_typing_detection = GetPropertyFromConstraints( 321 MediaAudioConstraints::kGoogTypingNoiseDetection);
326 &native_constraints, MediaConstraintsInterface::kTypingNoiseDetection);
327 #endif 322 #endif
328 323
329 const bool enable_ns = GetPropertyFromConstraints( 324 const bool goog_ns = audio_constraints.GetProperty(
330 &native_constraints, MediaConstraintsInterface::kNoiseSuppression); 325 MediaAudioConstraints::kGoogNoiseSuppression);
331 const bool enable_experimental_ns = GetPropertyFromConstraints( 326 const bool goog_experimental_ns = audio_constraints.GetProperty(
332 &native_constraints, 327 MediaAudioConstraints::kGoogExperimentalNoiseSuppression);
333 MediaConstraintsInterface::kExperimentalNoiseSuppression); 328 const bool goog_high_pass_filter = audio_constraints.GetProperty(
334 const bool enable_high_pass_filter = GetPropertyFromConstraints( 329 MediaAudioConstraints::kGoogHighpassFilter);
335 &native_constraints, MediaConstraintsInterface::kHighpassFilter);
336 330
337 // Return immediately if no audio processing component is enabled. 331 // Return immediately if no goog constraint is enabled.
338 if (!enable_aec && !enable_experimental_aec && !enable_ns && 332 if (!goog_aec && !goog_experimental_aec && !goog_ns &&
339 !enable_high_pass_filter && !enable_typing_detection && !enable_agc && 333 !goog_high_pass_filter && !goog_typing_detection &&
340 !enable_experimental_ns) { 334 !goog_agc && !goog_experimental_ns) {
341 RecordProcessingState(AUDIO_PROCESSING_DISABLED); 335 RecordProcessingState(AUDIO_PROCESSING_DISABLED);
342 return; 336 return;
343 } 337 }
344 338
345 // Create and configure the webrtc::AudioProcessing. 339 // Create and configure the webrtc::AudioProcessing.
346 audio_processing_.reset(webrtc::AudioProcessing::Create(0)); 340 audio_processing_.reset(webrtc::AudioProcessing::Create(0));
347 341
348 // Enable the audio processing components. 342 // Enable the audio processing components.
349 if (enable_aec) { 343 if (goog_aec) {
350 EnableEchoCancellation(audio_processing_.get()); 344 EnableEchoCancellation(audio_processing_.get());
351 if (enable_experimental_aec) 345
346 if (goog_experimental_aec)
352 EnableExperimentalEchoCancellation(audio_processing_.get()); 347 EnableExperimentalEchoCancellation(audio_processing_.get());
353 348
354 if (playout_data_source_) 349 if (playout_data_source_)
355 playout_data_source_->AddPlayoutSink(this); 350 playout_data_source_->AddPlayoutSink(this);
356 } 351 }
357 352
358 if (enable_ns) 353 if (goog_ns)
359 EnableNoiseSuppression(audio_processing_.get()); 354 EnableNoiseSuppression(audio_processing_.get());
360 355
361 if (enable_experimental_ns) 356 if (goog_experimental_ns)
362 EnableExperimentalNoiseSuppression(audio_processing_.get()); 357 EnableExperimentalNoiseSuppression(audio_processing_.get());
363 358
364 if (enable_high_pass_filter) 359 if (goog_high_pass_filter)
365 EnableHighPassFilter(audio_processing_.get()); 360 EnableHighPassFilter(audio_processing_.get());
366 361
367 if (enable_typing_detection) { 362 if (goog_typing_detection) {
368 // TODO(xians): Remove this |typing_detector_| after the typing suppression 363 // TODO(xians): Remove this |typing_detector_| after the typing suppression
369 // is enabled by default. 364 // is enabled by default.
370 typing_detector_.reset(new webrtc::TypingDetection()); 365 typing_detector_.reset(new webrtc::TypingDetection());
371 EnableTypingDetection(audio_processing_.get(), typing_detector_.get()); 366 EnableTypingDetection(audio_processing_.get(), typing_detector_.get());
372 } 367 }
373 368
374 if (enable_agc) 369 if (goog_agc)
375 EnableAutomaticGainControl(audio_processing_.get()); 370 EnableAutomaticGainControl(audio_processing_.get());
376 371
377 // Configure the audio format the audio processing is running on. This 372 // Configure the audio format the audio processing is running on. This
378 // has to be done after all the needed components are enabled. 373 // has to be done after all the needed components are enabled.
379 CHECK_EQ(0, 374 CHECK_EQ(0,
380 audio_processing_->set_sample_rate_hz(kAudioProcessingSampleRate)); 375 audio_processing_->set_sample_rate_hz(kAudioProcessingSampleRate));
381 CHECK_EQ(0, audio_processing_->set_num_channels( 376 CHECK_EQ(0, audio_processing_->set_num_channels(
382 kAudioProcessingNumberOfChannels, kAudioProcessingNumberOfChannels)); 377 kAudioProcessingNumberOfChannels, kAudioProcessingNumberOfChannels));
383 378
384 RecordProcessingState(AUDIO_PROCESSING_ENABLED); 379 RecordProcessingState(AUDIO_PROCESSING_ENABLED);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 audio_processing_->set_stream_key_pressed(key_pressed); 476 audio_processing_->set_stream_key_pressed(key_pressed);
482 477
483 err = audio_processing_->ProcessStream(audio_frame); 478 err = audio_processing_->ProcessStream(audio_frame);
484 DCHECK_EQ(err, 0) << "ProcessStream() error: " << err; 479 DCHECK_EQ(err, 0) << "ProcessStream() error: " << err;
485 480
486 if (typing_detector_ && 481 if (typing_detector_ &&
487 audio_frame->vad_activity_ != webrtc::AudioFrame::kVadUnknown) { 482 audio_frame->vad_activity_ != webrtc::AudioFrame::kVadUnknown) {
488 bool vad_active = 483 bool vad_active =
489 (audio_frame->vad_activity_ == webrtc::AudioFrame::kVadActive); 484 (audio_frame->vad_activity_ == webrtc::AudioFrame::kVadActive);
490 bool typing_detected = typing_detector_->Process(key_pressed, vad_active); 485 bool typing_detected = typing_detector_->Process(key_pressed, vad_active);
491 base::subtle::Release_Store(&typing_detected_, typing_detected); 486 base::subtle::Release_Store(&goog_typing_detected_, typing_detected);
492 } 487 }
493 488
494 // Return 0 if the volume has not been changed, otherwise return the new 489 // Return 0 if the volume has not been changed, otherwise return the new
495 // volume. 490 // volume.
496 return (agc->stream_analog_level() == volume) ? 491 return (agc->stream_analog_level() == volume) ?
497 0 : agc->stream_analog_level(); 492 0 : agc->stream_analog_level();
498 } 493 }
499 494
500 void MediaStreamAudioProcessor::StopAudioProcessing() { 495 void MediaStreamAudioProcessor::StopAudioProcessing() {
501 if (!audio_processing_.get()) 496 if (!audio_processing_.get())
502 return; 497 return;
503 498
504 StopAecDump(); 499 StopAecDump();
505 500
506 if (playout_data_source_) 501 if (playout_data_source_)
507 playout_data_source_->RemovePlayoutSink(this); 502 playout_data_source_->RemovePlayoutSink(this);
508 503
509 audio_processing_.reset(); 504 audio_processing_.reset();
510 } 505 }
511 506
512 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() const { 507 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() const {
513 const std::string group_name = 508 const std::string group_name =
514 base::FieldTrialList::FindFullName("MediaStreamAudioTrackProcessing"); 509 base::FieldTrialList::FindFullName("MediaStreamAudioTrackProcessing");
515 return group_name == "Enabled" || CommandLine::ForCurrentProcess()->HasSwitch( 510 return group_name == "Enabled" || CommandLine::ForCurrentProcess()->HasSwitch(
516 switches::kEnableAudioTrackProcessing); 511 switches::kEnableAudioTrackProcessing);
517 } 512 }
518 513
519 } // namespace content 514 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698