| OLD | NEW |
| 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/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/trace_event/trace_event.h" | 10 #include "base/trace_event/trace_event.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 "content/renderer/media/webrtc_audio_device_impl.h" | 14 #include "content/renderer/media/webrtc_audio_device_impl.h" |
| 15 #include "media/audio/audio_parameters.h" | 15 #include "media/audio/audio_parameters.h" |
| 16 #include "media/base/audio_converter.h" | 16 #include "media/base/audio_converter.h" |
| 17 #include "media/base/audio_fifo.h" | 17 #include "media/base/audio_fifo.h" |
| 18 #include "media/base/channel_layout.h" | 18 #include "media/base/channel_layout.h" |
| 19 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" | 19 #include "third_party/WebKit/public/platform/WebMediaConstraints.h" |
| 20 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface
.h" | 20 #include "third_party/libjingle/source/talk/app/webrtc/mediaconstraintsinterface
.h" |
| 21 #include "third_party/webrtc/modules/audio_processing/typing_detection.h" | 21 #include "third_party/webrtc/modules/audio_processing/typing_detection.h" |
| 22 | 22 |
| 23 #if defined(OS_CHROMEOS) | |
| 24 #include "base/sys_info.h" | |
| 25 #endif | |
| 26 | |
| 27 namespace content { | 23 namespace content { |
| 28 | 24 |
| 29 namespace { | 25 namespace { |
| 30 | 26 |
| 31 using webrtc::AudioProcessing; | 27 using webrtc::AudioProcessing; |
| 32 using webrtc::NoiseSuppression; | 28 using webrtc::NoiseSuppression; |
| 33 | 29 |
| 34 const int kAudioProcessingNumberOfChannels = 1; | 30 const int kAudioProcessingNumberOfChannels = 1; |
| 35 | 31 |
| 36 AudioProcessing::ChannelLayout MapLayout(media::ChannelLayout media_layout) { | 32 AudioProcessing::ChannelLayout MapLayout(media::ChannelLayout media_layout) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 | 82 |
| 87 return (group_name == "Enabled" || group_name == "DefaultEnabled"); | 83 return (group_name == "Enabled" || group_name == "DefaultEnabled"); |
| 88 } | 84 } |
| 89 | 85 |
| 90 bool IsBeamformingEnabled(const MediaAudioConstraints& audio_constraints) { | 86 bool IsBeamformingEnabled(const MediaAudioConstraints& audio_constraints) { |
| 91 return base::FieldTrialList::FindFullName("ChromebookBeamforming") == | 87 return base::FieldTrialList::FindFullName("ChromebookBeamforming") == |
| 92 "Enabled" || | 88 "Enabled" || |
| 93 audio_constraints.GetProperty(MediaAudioConstraints::kGoogBeamforming); | 89 audio_constraints.GetProperty(MediaAudioConstraints::kGoogBeamforming); |
| 94 } | 90 } |
| 95 | 91 |
| 96 void ConfigureBeamforming(webrtc::Config* config, | |
| 97 const std::string& geometry_str) { | |
| 98 std::vector<webrtc::Point> geometry = ParseArrayGeometry(geometry_str); | |
| 99 #if defined(OS_CHROMEOS) | |
| 100 if (geometry.empty()) { | |
| 101 const std::string& board = base::SysInfo::GetLsbReleaseBoard(); | |
| 102 if (board.find("nyan_kitty") != std::string::npos) { | |
| 103 geometry.push_back(webrtc::Point(-0.03f, 0.f, 0.f)); | |
| 104 geometry.push_back(webrtc::Point(0.03f, 0.f, 0.f)); | |
| 105 } else if (board.find("peach_pi") != std::string::npos) { | |
| 106 geometry.push_back(webrtc::Point(-0.025f, 0.f, 0.f)); | |
| 107 geometry.push_back(webrtc::Point(0.025f, 0.f, 0.f)); | |
| 108 } else if (board.find("samus") != std::string::npos) { | |
| 109 geometry.push_back(webrtc::Point(-0.032f, 0.f, 0.f)); | |
| 110 geometry.push_back(webrtc::Point(0.032f, 0.f, 0.f)); | |
| 111 } else if (board.find("swanky") != std::string::npos) { | |
| 112 geometry.push_back(webrtc::Point(-0.026f, 0.f, 0.f)); | |
| 113 geometry.push_back(webrtc::Point(0.026f, 0.f, 0.f)); | |
| 114 } | |
| 115 } | |
| 116 #endif | |
| 117 config->Set<webrtc::Beamforming>( | |
| 118 new webrtc::Beamforming(geometry.size() > 1, geometry)); | |
| 119 } | |
| 120 | |
| 121 } // namespace | 92 } // namespace |
| 122 | 93 |
| 123 // Wraps AudioBus to provide access to the array of channel pointers, since this | 94 // Wraps AudioBus to provide access to the array of channel pointers, since this |
| 124 // is the type webrtc::AudioProcessing deals in. The array is refreshed on every | 95 // is the type webrtc::AudioProcessing deals in. The array is refreshed on every |
| 125 // channel_ptrs() call, and will be valid until the underlying AudioBus pointers | 96 // channel_ptrs() call, and will be valid until the underlying AudioBus pointers |
| 126 // are changed, e.g. through calls to SetChannelData() or SwapChannels(). | 97 // are changed, e.g. through calls to SetChannelData() or SwapChannels(). |
| 127 // | 98 // |
| 128 // All methods are called on one of the capture or render audio threads | 99 // All methods are called on one of the capture or render audio threads |
| 129 // exclusively. | 100 // exclusively. |
| 130 class MediaStreamAudioBus { | 101 class MediaStreamAudioBus { |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 // delay of the first sample in |destination_|. | 235 // delay of the first sample in |destination_|. |
| 265 base::TimeDelta next_audio_delay_; | 236 base::TimeDelta next_audio_delay_; |
| 266 | 237 |
| 267 // True when |destination_| contains the data to be returned by the next call | 238 // True when |destination_| contains the data to be returned by the next call |
| 268 // to Consume(). Only used when the FIFO is disabled. | 239 // to Consume(). Only used when the FIFO is disabled. |
| 269 bool data_available_; | 240 bool data_available_; |
| 270 }; | 241 }; |
| 271 | 242 |
| 272 MediaStreamAudioProcessor::MediaStreamAudioProcessor( | 243 MediaStreamAudioProcessor::MediaStreamAudioProcessor( |
| 273 const blink::WebMediaConstraints& constraints, | 244 const blink::WebMediaConstraints& constraints, |
| 274 int effects, | 245 const MediaStreamDevice::AudioDeviceParameters& input_params, |
| 275 WebRtcPlayoutDataSource* playout_data_source) | 246 WebRtcPlayoutDataSource* playout_data_source) |
| 276 : render_delay_ms_(0), | 247 : render_delay_ms_(0), |
| 277 playout_data_source_(playout_data_source), | 248 playout_data_source_(playout_data_source), |
| 278 audio_mirroring_(false), | 249 audio_mirroring_(false), |
| 279 typing_detected_(false), | 250 typing_detected_(false), |
| 280 stopped_(false) { | 251 stopped_(false) { |
| 281 capture_thread_checker_.DetachFromThread(); | 252 capture_thread_checker_.DetachFromThread(); |
| 282 render_thread_checker_.DetachFromThread(); | 253 render_thread_checker_.DetachFromThread(); |
| 283 InitializeAudioProcessingModule(constraints, effects); | 254 InitializeAudioProcessingModule(constraints, input_params); |
| 284 | 255 |
| 285 aec_dump_message_filter_ = AecDumpMessageFilter::Get(); | 256 aec_dump_message_filter_ = AecDumpMessageFilter::Get(); |
| 286 // In unit tests not creating a message filter, |aec_dump_message_filter_| | 257 // In unit tests not creating a message filter, |aec_dump_message_filter_| |
| 287 // will be NULL. We can just ignore that. Other unit tests and browser tests | 258 // will be NULL. We can just ignore that. Other unit tests and browser tests |
| 288 // ensure that we do get the filter when we should. | 259 // ensure that we do get the filter when we should. |
| 289 if (aec_dump_message_filter_.get()) | 260 if (aec_dump_message_filter_.get()) |
| 290 aec_dump_message_filter_->AddDelegate(this); | 261 aec_dump_message_filter_->AddDelegate(this); |
| 291 } | 262 } |
| 292 | 263 |
| 293 MediaStreamAudioProcessor::~MediaStreamAudioProcessor() { | 264 MediaStreamAudioProcessor::~MediaStreamAudioProcessor() { |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 render_fifo_.reset(); | 419 render_fifo_.reset(); |
| 449 } | 420 } |
| 450 | 421 |
| 451 void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) { | 422 void MediaStreamAudioProcessor::GetStats(AudioProcessorStats* stats) { |
| 452 stats->typing_noise_detected = | 423 stats->typing_noise_detected = |
| 453 (base::subtle::Acquire_Load(&typing_detected_) != false); | 424 (base::subtle::Acquire_Load(&typing_detected_) != false); |
| 454 GetAecStats(audio_processing_.get()->echo_cancellation(), stats); | 425 GetAecStats(audio_processing_.get()->echo_cancellation(), stats); |
| 455 } | 426 } |
| 456 | 427 |
| 457 void MediaStreamAudioProcessor::InitializeAudioProcessingModule( | 428 void MediaStreamAudioProcessor::InitializeAudioProcessingModule( |
| 458 const blink::WebMediaConstraints& constraints, int effects) { | 429 const blink::WebMediaConstraints& constraints, |
| 430 const MediaStreamDevice::AudioDeviceParameters& input_params) { |
| 459 DCHECK(main_thread_checker_.CalledOnValidThread()); | 431 DCHECK(main_thread_checker_.CalledOnValidThread()); |
| 460 DCHECK(!audio_processing_); | 432 DCHECK(!audio_processing_); |
| 461 | 433 |
| 462 MediaAudioConstraints audio_constraints(constraints, effects); | 434 MediaAudioConstraints audio_constraints(constraints, input_params.effects); |
| 463 | 435 |
| 464 // Audio mirroring can be enabled even though audio processing is otherwise | 436 // Audio mirroring can be enabled even though audio processing is otherwise |
| 465 // disabled. | 437 // disabled. |
| 466 audio_mirroring_ = audio_constraints.GetProperty( | 438 audio_mirroring_ = audio_constraints.GetProperty( |
| 467 MediaAudioConstraints::kGoogAudioMirroring); | 439 MediaAudioConstraints::kGoogAudioMirroring); |
| 468 | 440 |
| 469 #if defined(OS_IOS) | 441 #if defined(OS_IOS) |
| 470 // On iOS, VPIO provides built-in AGC and AEC. | 442 // On iOS, VPIO provides built-in AGC and AEC. |
| 471 const bool echo_cancellation = false; | 443 const bool echo_cancellation = false; |
| 472 const bool goog_agc = false; | 444 const bool goog_agc = false; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 504 | 476 |
| 505 // Experimental options provided at creation. | 477 // Experimental options provided at creation. |
| 506 webrtc::Config config; | 478 webrtc::Config config; |
| 507 if (goog_experimental_aec) | 479 if (goog_experimental_aec) |
| 508 config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true)); | 480 config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true)); |
| 509 if (goog_experimental_ns) | 481 if (goog_experimental_ns) |
| 510 config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(true)); | 482 config.Set<webrtc::ExperimentalNs>(new webrtc::ExperimentalNs(true)); |
| 511 if (IsDelayAgnosticAecEnabled()) | 483 if (IsDelayAgnosticAecEnabled()) |
| 512 config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(true)); | 484 config.Set<webrtc::DelayAgnostic>(new webrtc::DelayAgnostic(true)); |
| 513 if (goog_beamforming) { | 485 if (goog_beamforming) { |
| 514 ConfigureBeamforming(&config, | 486 const auto& geometry = |
| 515 audio_constraints.GetPropertyAsString( | 487 GetArrayGeometryPreferringConstraints(audio_constraints, input_params); |
| 516 MediaAudioConstraints::kGoogArrayGeometry)); | 488 |
| 489 // Only enable beamforming if we have at least two mics. |
| 490 config.Set<webrtc::Beamforming>( |
| 491 new webrtc::Beamforming(geometry.size() > 1, geometry)); |
| 517 } | 492 } |
| 518 | 493 |
| 519 // Create and configure the webrtc::AudioProcessing. | 494 // Create and configure the webrtc::AudioProcessing. |
| 520 audio_processing_.reset(webrtc::AudioProcessing::Create(config)); | 495 audio_processing_.reset(webrtc::AudioProcessing::Create(config)); |
| 521 | 496 |
| 522 // Enable the audio processing components. | 497 // Enable the audio processing components. |
| 523 if (echo_cancellation) { | 498 if (echo_cancellation) { |
| 524 EnableEchoCancellation(audio_processing_.get()); | 499 EnableEchoCancellation(audio_processing_.get()); |
| 525 | 500 |
| 526 if (playout_data_source_) | 501 if (playout_data_source_) |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 596 | 571 |
| 597 // webrtc::AudioProcessing requires a 10 ms chunk size. We use this native | 572 // webrtc::AudioProcessing requires a 10 ms chunk size. We use this native |
| 598 // size when processing is enabled. When disabled we use the same size as | 573 // size when processing is enabled. When disabled we use the same size as |
| 599 // the source if less than 10 ms. | 574 // the source if less than 10 ms. |
| 600 // | 575 // |
| 601 // TODO(ajm): This conditional buffer size appears to be assuming knowledge of | 576 // TODO(ajm): This conditional buffer size appears to be assuming knowledge of |
| 602 // the sink based on the source parameters. PeerConnection sinks seem to want | 577 // the sink based on the source parameters. PeerConnection sinks seem to want |
| 603 // 10 ms chunks regardless, while WebAudio sinks want less, and we're assuming | 578 // 10 ms chunks regardless, while WebAudio sinks want less, and we're assuming |
| 604 // we can identify WebAudio sinks by the input chunk size. Less fragile would | 579 // we can identify WebAudio sinks by the input chunk size. Less fragile would |
| 605 // be to have the sink actually tell us how much it wants (as in the above | 580 // be to have the sink actually tell us how much it wants (as in the above |
| 606 // TODO). | 581 // todo). |
| 607 int processing_frames = input_format.sample_rate() / 100; | 582 int processing_frames = input_format.sample_rate() / 100; |
| 608 int output_frames = output_sample_rate / 100; | 583 int output_frames = output_sample_rate / 100; |
| 609 if (!audio_processing_ && input_format.frames_per_buffer() < output_frames) { | 584 if (!audio_processing_ && input_format.frames_per_buffer() < output_frames) { |
| 610 processing_frames = input_format.frames_per_buffer(); | 585 processing_frames = input_format.frames_per_buffer(); |
| 611 output_frames = processing_frames; | 586 output_frames = processing_frames; |
| 612 } | 587 } |
| 613 | 588 |
| 614 output_format_ = media::AudioParameters( | 589 output_format_ = media::AudioParameters( |
| 615 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 590 media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 616 output_channel_layout, | 591 output_channel_layout, |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 if (echo_information_) { | 685 if (echo_information_) { |
| 711 echo_information_.get()->UpdateAecDelayStats(ap->echo_cancellation()); | 686 echo_information_.get()->UpdateAecDelayStats(ap->echo_cancellation()); |
| 712 } | 687 } |
| 713 | 688 |
| 714 // Return 0 if the volume hasn't been changed, and otherwise the new volume. | 689 // Return 0 if the volume hasn't been changed, and otherwise the new volume. |
| 715 return (agc->stream_analog_level() == volume) ? | 690 return (agc->stream_analog_level() == volume) ? |
| 716 0 : agc->stream_analog_level(); | 691 0 : agc->stream_analog_level(); |
| 717 } | 692 } |
| 718 | 693 |
| 719 } // namespace content | 694 } // namespace content |
| OLD | NEW |