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

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: addressed Per's comments. 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);
284 281
285 // Audio mirroring can be enabled even though audio processing is otherwise 282 // Audio mirroring can be enabled even though audio processing is otherwise
286 // disabled. 283 // disabled.
287 audio_mirroring_ = GetPropertyFromConstraints( 284 goog_audio_mirroring_ = audio_constraints.GetProperty(
288 &native_constraints, webrtc::MediaConstraintsInterface::kAudioMirroring); 285 MediaAudioConstraints::kGoogAudioMirroring);
289 286
290 if (!IsAudioTrackProcessingEnabled()) { 287 if (!IsAudioTrackProcessingEnabled()) {
291 RecordProcessingState(AUDIO_PROCESSING_IN_WEBRTC); 288 RecordProcessingState(AUDIO_PROCESSING_IN_WEBRTC);
292 return; 289 return;
293 } 290 }
294 291
295 // Only apply the fixed constraints for gUM of MEDIA_DEVICE_AUDIO_CAPTURE. 292 // |kEchoCancellation| is used as a master control on enabling/disabling
296 DCHECK(IsAudioMediaType(type)); 293 // the audio processing.
297 if (type == MEDIA_DEVICE_AUDIO_CAPTURE) 294 const bool echo_cancellation = audio_constraints.GetProperty(
ajm 2014/04/15 01:29:58 Is this defaulted to true, and only overridden if
no longer working on chromium 2014/04/15 12:43:46 Yes.
ajm 2014/04/16 05:17:43 Ah, OK. I see you have a TODO below to deal with t
298 ApplyFixedAudioConstraints(&native_constraints); 295 MediaAudioConstraints::kEchoCancellation);
tommi (sloooow) - chröme 2014/04/17 10:56:41 It's not clear from the code that the return value
no longer working on chromium 2014/04/23 14:59:06 Done. FYI, there is also comment in MediaAudioCon
299 296 if (!echo_cancellation) {
300 if (effects & media::AudioParameters::ECHO_CANCELLER) { 297 RecordProcessingState(AUDIO_PROCESSING_DISABLED);
301 // If platform echo canceller is enabled, disable the software AEC. 298 return;
302 native_constraints.AddMandatory(
303 MediaConstraintsInterface::kEchoCancellation,
304 MediaConstraintsInterface::kValueFalse, true);
305 } 299 }
306 300
307 #if defined(OS_IOS) 301 #if defined(OS_IOS)
308 // On iOS, VPIO provides built-in AEC and AGC. 302 // On iOS, VPIO provides built-in AEC and AGC.
309 const bool enable_aec = false; 303 const bool goog_aec = false;
ajm 2014/04/15 01:29:58 I'm not sure that having these match the constrain
no longer working on chromium 2014/04/15 12:43:46 The change is to avoid the confusion between stand
ajm 2014/04/16 05:17:43 OK, I can buy it.
310 const bool enable_agc = false; 304 const bool goog_agc = false;
311 #else 305 #else
312 const bool enable_aec = GetPropertyFromConstraints( 306 // TODO(xians): goog_aec should be just echo_cancellation.
tommi (sloooow) - chröme 2014/04/17 10:56:41 Here I think we need to only check the value of kG
no longer working on chromium 2014/04/23 14:59:06 Done with taking care the case where kEchoCancella
313 &native_constraints, MediaConstraintsInterface::kEchoCancellation); 307 const bool goog_aec = audio_constraints.GetProperty(
314 const bool enable_agc = GetPropertyFromConstraints( 308 MediaAudioConstraints::kGoogEchoCancellation);
315 &native_constraints, webrtc::MediaConstraintsInterface::kAutoGainControl); 309 const bool goog_agc = audio_constraints.GetProperty(
310 MediaAudioConstraints::kGoogAutoGainControl);
316 #endif 311 #endif
317 312
318 #if defined(OS_IOS) || defined(OS_ANDROID) 313 #if defined(OS_IOS) || defined(OS_ANDROID)
319 const bool enable_experimental_aec = false; 314 const bool goog_experimental_aec = false;
320 const bool enable_typing_detection = false; 315 const bool goog_typing_detection = false;
321 #else 316 #else
322 const bool enable_experimental_aec = GetPropertyFromConstraints( 317 const bool goog_experimental_aec = audio_constraints.GetProperty(
323 &native_constraints, 318 MediaAudioConstraints::kGoogExperimentalEchoCancellation);
324 MediaConstraintsInterface::kExperimentalEchoCancellation); 319 const bool goog_typing_detection = audio_constraints.GetProperty(
325 const bool enable_typing_detection = GetPropertyFromConstraints( 320 MediaAudioConstraints::kGoogTypingNoiseDetection);
326 &native_constraints, MediaConstraintsInterface::kTypingNoiseDetection);
327 #endif 321 #endif
328 322
329 const bool enable_ns = GetPropertyFromConstraints( 323 const bool goog_ns = audio_constraints.GetProperty(
330 &native_constraints, MediaConstraintsInterface::kNoiseSuppression); 324 MediaAudioConstraints::kGoogNoiseSuppression);
331 const bool enable_experimental_ns = GetPropertyFromConstraints( 325 const bool goog_experimental_ns = audio_constraints.GetProperty(
332 &native_constraints, 326 MediaAudioConstraints::kGoogExperimentalNoiseSuppression);
333 MediaConstraintsInterface::kExperimentalNoiseSuppression); 327 const bool goog_high_pass_filter = audio_constraints.GetProperty(
334 const bool enable_high_pass_filter = GetPropertyFromConstraints( 328 MediaAudioConstraints::kGoogHighpassFilter);
335 &native_constraints, MediaConstraintsInterface::kHighpassFilter);
336 329
337 // Return immediately if no audio processing component is enabled. 330 // Return immediately if no goog constraint is enabled.
tommi (sloooow) - chröme 2014/04/17 10:56:41 Can you add that in this case the goog constraints
no longer working on chromium 2014/04/23 14:59:06 No, we can't. The constraints can be whatever JS d
338 if (!enable_aec && !enable_experimental_aec && !enable_ns && 331 if (!goog_aec && !goog_experimental_aec && !goog_ns &&
339 !enable_high_pass_filter && !enable_typing_detection && !enable_agc && 332 !goog_high_pass_filter && !goog_typing_detection &&
340 !enable_experimental_ns) { 333 !goog_agc && !goog_experimental_ns) {
341 RecordProcessingState(AUDIO_PROCESSING_DISABLED); 334 RecordProcessingState(AUDIO_PROCESSING_DISABLED);
342 return; 335 return;
343 } 336 }
344 337
345 // Create and configure the webrtc::AudioProcessing. 338 // Create and configure the webrtc::AudioProcessing.
346 audio_processing_.reset(webrtc::AudioProcessing::Create(0)); 339 audio_processing_.reset(webrtc::AudioProcessing::Create(0));
347 340
348 // Enable the audio processing components. 341 // Enable the audio processing components.
349 if (enable_aec) { 342 if (goog_aec) {
350 EnableEchoCancellation(audio_processing_.get()); 343 EnableEchoCancellation(audio_processing_.get());
351 if (enable_experimental_aec) 344
345 if (goog_experimental_aec)
352 EnableExperimentalEchoCancellation(audio_processing_.get()); 346 EnableExperimentalEchoCancellation(audio_processing_.get());
353 347
354 if (playout_data_source_) 348 if (playout_data_source_)
355 playout_data_source_->AddPlayoutSink(this); 349 playout_data_source_->AddPlayoutSink(this);
356 } 350 }
357 351
358 if (enable_ns) 352 if (goog_ns)
359 EnableNoiseSuppression(audio_processing_.get()); 353 EnableNoiseSuppression(audio_processing_.get());
360 354
361 if (enable_experimental_ns) 355 if (goog_experimental_ns)
362 EnableExperimentalNoiseSuppression(audio_processing_.get()); 356 EnableExperimentalNoiseSuppression(audio_processing_.get());
363 357
364 if (enable_high_pass_filter) 358 if (goog_high_pass_filter)
365 EnableHighPassFilter(audio_processing_.get()); 359 EnableHighPassFilter(audio_processing_.get());
366 360
367 if (enable_typing_detection) { 361 if (goog_typing_detection) {
368 // TODO(xians): Remove this |typing_detector_| after the typing suppression 362 // TODO(xians): Remove this |typing_detector_| after the typing suppression
369 // is enabled by default. 363 // is enabled by default.
370 typing_detector_.reset(new webrtc::TypingDetection()); 364 typing_detector_.reset(new webrtc::TypingDetection());
371 EnableTypingDetection(audio_processing_.get(), typing_detector_.get()); 365 EnableTypingDetection(audio_processing_.get(), typing_detector_.get());
372 } 366 }
373 367
374 if (enable_agc) 368 if (goog_agc)
375 EnableAutomaticGainControl(audio_processing_.get()); 369 EnableAutomaticGainControl(audio_processing_.get());
376 370
377 // Configure the audio format the audio processing is running on. This 371 // Configure the audio format the audio processing is running on. This
378 // has to be done after all the needed components are enabled. 372 // has to be done after all the needed components are enabled.
379 CHECK_EQ(0, 373 CHECK_EQ(0,
380 audio_processing_->set_sample_rate_hz(kAudioProcessingSampleRate)); 374 audio_processing_->set_sample_rate_hz(kAudioProcessingSampleRate));
381 CHECK_EQ(0, audio_processing_->set_num_channels( 375 CHECK_EQ(0, audio_processing_->set_num_channels(
382 kAudioProcessingNumberOfChannels, kAudioProcessingNumberOfChannels)); 376 kAudioProcessingNumberOfChannels, kAudioProcessingNumberOfChannels));
383 377
384 RecordProcessingState(AUDIO_PROCESSING_ENABLED); 378 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); 475 audio_processing_->set_stream_key_pressed(key_pressed);
482 476
483 err = audio_processing_->ProcessStream(audio_frame); 477 err = audio_processing_->ProcessStream(audio_frame);
484 DCHECK_EQ(err, 0) << "ProcessStream() error: " << err; 478 DCHECK_EQ(err, 0) << "ProcessStream() error: " << err;
485 479
486 if (typing_detector_ && 480 if (typing_detector_ &&
487 audio_frame->vad_activity_ != webrtc::AudioFrame::kVadUnknown) { 481 audio_frame->vad_activity_ != webrtc::AudioFrame::kVadUnknown) {
488 bool vad_active = 482 bool vad_active =
489 (audio_frame->vad_activity_ == webrtc::AudioFrame::kVadActive); 483 (audio_frame->vad_activity_ == webrtc::AudioFrame::kVadActive);
490 bool typing_detected = typing_detector_->Process(key_pressed, vad_active); 484 bool typing_detected = typing_detector_->Process(key_pressed, vad_active);
491 base::subtle::Release_Store(&typing_detected_, typing_detected); 485 base::subtle::Release_Store(&goog_typing_detected_, typing_detected);
492 } 486 }
493 487
494 // Return 0 if the volume has not been changed, otherwise return the new 488 // Return 0 if the volume has not been changed, otherwise return the new
495 // volume. 489 // volume.
496 return (agc->stream_analog_level() == volume) ? 490 return (agc->stream_analog_level() == volume) ?
497 0 : agc->stream_analog_level(); 491 0 : agc->stream_analog_level();
498 } 492 }
499 493
500 void MediaStreamAudioProcessor::StopAudioProcessing() { 494 void MediaStreamAudioProcessor::StopAudioProcessing() {
501 if (!audio_processing_.get()) 495 if (!audio_processing_.get())
502 return; 496 return;
503 497
504 StopAecDump(); 498 StopAecDump();
505 499
506 if (playout_data_source_) 500 if (playout_data_source_)
507 playout_data_source_->RemovePlayoutSink(this); 501 playout_data_source_->RemovePlayoutSink(this);
508 502
509 audio_processing_.reset(); 503 audio_processing_.reset();
510 } 504 }
511 505
512 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() const { 506 bool MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() const {
513 const std::string group_name = 507 const std::string group_name =
514 base::FieldTrialList::FindFullName("MediaStreamAudioTrackProcessing"); 508 base::FieldTrialList::FindFullName("MediaStreamAudioTrackProcessing");
515 return group_name == "Enabled" || CommandLine::ForCurrentProcess()->HasSwitch( 509 return group_name == "Enabled" || CommandLine::ForCurrentProcess()->HasSwitch(
516 switches::kEnableAudioTrackProcessing); 510 switches::kEnableAudioTrackProcessing);
517 } 511 }
518 512
519 } // namespace content 513 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698