| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/webrtc_audio_capturer.h" | 5 #include "content/renderer/media/webrtc_audio_capturer.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/logging.h" | 8 #include "base/logging.h" |
| 9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "base/strings/string_util.h" | 10 #include "base/strings/string_util.h" |
| (...skipping 29 matching lines...) Expand all Loading... |
| 40 } // namespace | 40 } // namespace |
| 41 | 41 |
| 42 // Reference counted container of WebRtcLocalAudioTrack delegate. | 42 // Reference counted container of WebRtcLocalAudioTrack delegate. |
| 43 // TODO(xians): Switch to MediaStreamAudioSinkOwner. | 43 // TODO(xians): Switch to MediaStreamAudioSinkOwner. |
| 44 class WebRtcAudioCapturer::TrackOwner | 44 class WebRtcAudioCapturer::TrackOwner |
| 45 : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> { | 45 : public base::RefCountedThreadSafe<WebRtcAudioCapturer::TrackOwner> { |
| 46 public: | 46 public: |
| 47 explicit TrackOwner(WebRtcLocalAudioTrack* track) | 47 explicit TrackOwner(WebRtcLocalAudioTrack* track) |
| 48 : delegate_(track) {} | 48 : delegate_(track) {} |
| 49 | 49 |
| 50 void Capture(const int16* audio_data, | 50 void Capture(const int16* audio_data, bool force_report_nonzero_energy) { |
| 51 base::TimeDelta delay, | |
| 52 double volume, | |
| 53 bool key_pressed, | |
| 54 bool need_audio_processing, | |
| 55 bool force_report_nonzero_energy) { | |
| 56 base::AutoLock lock(lock_); | 51 base::AutoLock lock(lock_); |
| 57 if (delegate_) { | 52 if (delegate_) { |
| 58 delegate_->Capture(audio_data, | 53 delegate_->Capture(audio_data, force_report_nonzero_energy); |
| 59 delay, | |
| 60 volume, | |
| 61 key_pressed, | |
| 62 need_audio_processing, | |
| 63 force_report_nonzero_energy); | |
| 64 } | 54 } |
| 65 } | 55 } |
| 66 | 56 |
| 67 void OnSetFormat(const media::AudioParameters& params) { | 57 void OnSetFormat(const media::AudioParameters& params) { |
| 68 base::AutoLock lock(lock_); | 58 base::AutoLock lock(lock_); |
| 69 if (delegate_) | 59 if (delegate_) |
| 70 delegate_->OnSetFormat(params); | 60 delegate_->OnSetFormat(params); |
| 71 } | 61 } |
| 72 | 62 |
| 73 void SetAudioProcessor( | 63 void SetAudioProcessor( |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 if (!audio_constraints.IsValid()) | 153 if (!audio_constraints.IsValid()) |
| 164 return false; | 154 return false; |
| 165 | 155 |
| 166 media::ChannelLayout channel_layout = static_cast<media::ChannelLayout>( | 156 media::ChannelLayout channel_layout = static_cast<media::ChannelLayout>( |
| 167 device_info_.device.input.channel_layout); | 157 device_info_.device.input.channel_layout); |
| 168 | 158 |
| 169 // If KEYBOARD_MIC effect is set, change the layout to the corresponding | 159 // If KEYBOARD_MIC effect is set, change the layout to the corresponding |
| 170 // layout that includes the keyboard mic. | 160 // layout that includes the keyboard mic. |
| 171 if ((device_info_.device.input.effects & | 161 if ((device_info_.device.input.effects & |
| 172 media::AudioParameters::KEYBOARD_MIC) && | 162 media::AudioParameters::KEYBOARD_MIC) && |
| 173 MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() && | |
| 174 audio_constraints.GetProperty( | 163 audio_constraints.GetProperty( |
| 175 MediaAudioConstraints::kGoogExperimentalNoiseSuppression)) { | 164 MediaAudioConstraints::kGoogExperimentalNoiseSuppression)) { |
| 176 if (channel_layout == media::CHANNEL_LAYOUT_STEREO) { | 165 if (channel_layout == media::CHANNEL_LAYOUT_STEREO) { |
| 177 channel_layout = media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC; | 166 channel_layout = media::CHANNEL_LAYOUT_STEREO_AND_KEYBOARD_MIC; |
| 178 DVLOG(1) << "Changed stereo layout to stereo + keyboard mic layout due " | 167 DVLOG(1) << "Changed stereo layout to stereo + keyboard mic layout due " |
| 179 << "to KEYBOARD_MIC effect."; | 168 << "to KEYBOARD_MIC effect."; |
| 180 } else { | 169 } else { |
| 181 DVLOG(1) << "KEYBOARD_MIC effect ignored, not compatible with layout " | 170 DVLOG(1) << "KEYBOARD_MIC effect ignored, not compatible with layout " |
| 182 << channel_layout; | 171 << channel_layout; |
| 183 } | 172 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 229 : constraints_(constraints), | 218 : constraints_(constraints), |
| 230 audio_processor_(new rtc::RefCountedObject<MediaStreamAudioProcessor>( | 219 audio_processor_(new rtc::RefCountedObject<MediaStreamAudioProcessor>( |
| 231 constraints, | 220 constraints, |
| 232 device_info.device.input.effects, | 221 device_info.device.input.effects, |
| 233 audio_device)), | 222 audio_device)), |
| 234 running_(false), | 223 running_(false), |
| 235 render_view_id_(render_view_id), | 224 render_view_id_(render_view_id), |
| 236 device_info_(device_info), | 225 device_info_(device_info), |
| 237 volume_(0), | 226 volume_(0), |
| 238 peer_connection_mode_(false), | 227 peer_connection_mode_(false), |
| 239 key_pressed_(false), | |
| 240 need_audio_processing_(false), | |
| 241 audio_device_(audio_device), | 228 audio_device_(audio_device), |
| 242 audio_source_(audio_source) { | 229 audio_source_(audio_source) { |
| 243 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; | 230 DVLOG(1) << "WebRtcAudioCapturer::WebRtcAudioCapturer()"; |
| 244 } | 231 } |
| 245 | 232 |
| 246 WebRtcAudioCapturer::~WebRtcAudioCapturer() { | 233 WebRtcAudioCapturer::~WebRtcAudioCapturer() { |
| 247 DCHECK(thread_checker_.CalledOnValidThread()); | 234 DCHECK(thread_checker_.CalledOnValidThread()); |
| 248 DCHECK(tracks_.IsEmpty()); | 235 DCHECK(tracks_.IsEmpty()); |
| 249 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; | 236 DVLOG(1) << "WebRtcAudioCapturer::~WebRtcAudioCapturer()"; |
| 250 Stop(); | 237 Stop(); |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, | 314 media::AudioParameters params(media::AudioParameters::AUDIO_PCM_LOW_LATENCY, |
| 328 channel_layout, sample_rate, | 315 channel_layout, sample_rate, |
| 329 16, buffer_size, | 316 16, buffer_size, |
| 330 device_info_.device.input.effects); | 317 device_info_.device.input.effects); |
| 331 | 318 |
| 332 { | 319 { |
| 333 base::AutoLock auto_lock(lock_); | 320 base::AutoLock auto_lock(lock_); |
| 334 // Notify the |audio_processor_| of the new format. | 321 // Notify the |audio_processor_| of the new format. |
| 335 audio_processor_->OnCaptureFormatChanged(params); | 322 audio_processor_->OnCaptureFormatChanged(params); |
| 336 | 323 |
| 337 MediaAudioConstraints audio_constraints(constraints_, | |
| 338 device_info_.device.input.effects); | |
| 339 need_audio_processing_ = audio_constraints.NeedsAudioProcessing(); | |
| 340 // Notify all tracks about the new format. | 324 // Notify all tracks about the new format. |
| 341 tracks_.TagAll(); | 325 tracks_.TagAll(); |
| 342 } | 326 } |
| 343 | 327 |
| 344 if (source.get()) | 328 if (source.get()) |
| 345 source->Initialize(params, this, session_id()); | 329 source->Initialize(params, this, session_id()); |
| 346 | 330 |
| 347 Start(); | 331 Start(); |
| 348 } | 332 } |
| 349 | 333 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 461 // allows the user to set a scaling that is higher than 100%. It means that | 445 // allows the user to set a scaling that is higher than 100%. It means that |
| 462 // even if the reported maximum levels is N, the actual microphone level can | 446 // even if the reported maximum levels is N, the actual microphone level can |
| 463 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x. | 447 // go up to 1.5x*N and that corresponds to a normalized |volume| of 1.5x. |
| 464 DCHECK_LE(volume, 1.6); | 448 DCHECK_LE(volume, 1.6); |
| 465 #endif | 449 #endif |
| 466 | 450 |
| 467 TrackList::ItemList tracks; | 451 TrackList::ItemList tracks; |
| 468 TrackList::ItemList tracks_to_notify_format; | 452 TrackList::ItemList tracks_to_notify_format; |
| 469 int current_volume = 0; | 453 int current_volume = 0; |
| 470 base::TimeDelta audio_delay; | 454 base::TimeDelta audio_delay; |
| 471 bool need_audio_processing = true; | |
| 472 { | 455 { |
| 473 base::AutoLock auto_lock(lock_); | 456 base::AutoLock auto_lock(lock_); |
| 474 if (!running_) | 457 if (!running_) |
| 475 return; | 458 return; |
| 476 | 459 |
| 477 // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC. | 460 // Map internal volume range of [0.0, 1.0] into [0, 255] used by AGC. |
| 478 // The volume can be higher than 255 on Linux, and it will be cropped to | 461 // The volume can be higher than 255 on Linux, and it will be cropped to |
| 479 // 255 since AGC does not allow values out of range. | 462 // 255 since AGC does not allow values out of range. |
| 480 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); | 463 volume_ = static_cast<int>((volume * MaxVolume()) + 0.5); |
| 481 current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_; | 464 current_volume = volume_ > MaxVolume() ? MaxVolume() : volume_; |
| 482 audio_delay = base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); | 465 audio_delay = base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); |
| 483 audio_delay_ = audio_delay; | |
| 484 key_pressed_ = key_pressed; | |
| 485 tracks = tracks_.Items(); | 466 tracks = tracks_.Items(); |
| 486 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); | 467 tracks_.RetrieveAndClearTags(&tracks_to_notify_format); |
| 487 | |
| 488 // Set the flag to turn on the audio processing in PeerConnection level. | |
| 489 // Note that, we turn off the audio processing in PeerConnection if the | |
| 490 // processor has already processed the data. | |
| 491 need_audio_processing = need_audio_processing_ ? | |
| 492 !MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled() : false; | |
| 493 } | 468 } |
| 494 | 469 |
| 495 DCHECK(audio_processor_->InputFormat().IsValid()); | 470 DCHECK(audio_processor_->InputFormat().IsValid()); |
| 496 DCHECK_EQ(audio_source->channels(), | 471 DCHECK_EQ(audio_source->channels(), |
| 497 audio_processor_->InputFormat().channels()); | 472 audio_processor_->InputFormat().channels()); |
| 498 DCHECK_EQ(audio_source->frames(), | 473 DCHECK_EQ(audio_source->frames(), |
| 499 audio_processor_->InputFormat().frames_per_buffer()); | 474 audio_processor_->InputFormat().frames_per_buffer()); |
| 500 | 475 |
| 501 // Notify the tracks on when the format changes. This will do nothing if | 476 // Notify the tracks on when the format changes. This will do nothing if |
| 502 // |tracks_to_notify_format| is empty. | 477 // |tracks_to_notify_format| is empty. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 518 | 493 |
| 519 // Process and consume the data in the processor until there is not enough | 494 // Process and consume the data in the processor until there is not enough |
| 520 // data in the processor. | 495 // data in the processor. |
| 521 int16* output = NULL; | 496 int16* output = NULL; |
| 522 int new_volume = 0; | 497 int new_volume = 0; |
| 523 while (audio_processor_->ProcessAndConsumeData( | 498 while (audio_processor_->ProcessAndConsumeData( |
| 524 audio_delay, current_volume, key_pressed, &new_volume, &output)) { | 499 audio_delay, current_volume, key_pressed, &new_volume, &output)) { |
| 525 // Feed the post-processed data to the tracks. | 500 // Feed the post-processed data to the tracks. |
| 526 for (TrackList::ItemList::const_iterator it = tracks.begin(); | 501 for (TrackList::ItemList::const_iterator it = tracks.begin(); |
| 527 it != tracks.end(); ++it) { | 502 it != tracks.end(); ++it) { |
| 528 (*it)->Capture(output, audio_delay, current_volume, key_pressed, | 503 (*it)->Capture(output, force_report_nonzero_energy); |
| 529 need_audio_processing, force_report_nonzero_energy); | |
| 530 } | 504 } |
| 531 | 505 |
| 532 if (new_volume) { | 506 if (new_volume) { |
| 533 SetVolume(new_volume); | 507 SetVolume(new_volume); |
| 534 | 508 |
| 535 // Update the |current_volume| to avoid passing the old volume to AGC. | 509 // Update the |current_volume| to avoid passing the old volume to AGC. |
| 536 current_volume = new_volume; | 510 current_volume = new_volume; |
| 537 } | 511 } |
| 538 } | 512 } |
| 539 } | 513 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 hardware_buffer_size <= peer_connection_buffer_size && | 559 hardware_buffer_size <= peer_connection_buffer_size && |
| 586 !audio_processor_->has_audio_processing()) { | 560 !audio_processor_->has_audio_processing()) { |
| 587 DVLOG(1) << "WebRtcAudioCapturer is using hardware buffer size " | 561 DVLOG(1) << "WebRtcAudioCapturer is using hardware buffer size " |
| 588 << hardware_buffer_size; | 562 << hardware_buffer_size; |
| 589 return hardware_buffer_size; | 563 return hardware_buffer_size; |
| 590 } | 564 } |
| 591 | 565 |
| 592 return (sample_rate / 100); | 566 return (sample_rate / 100); |
| 593 } | 567 } |
| 594 | 568 |
| 595 void WebRtcAudioCapturer::GetAudioProcessingParams( | |
| 596 base::TimeDelta* delay, int* volume, bool* key_pressed) { | |
| 597 base::AutoLock auto_lock(lock_); | |
| 598 *delay = audio_delay_; | |
| 599 *volume = volume_; | |
| 600 *key_pressed = key_pressed_; | |
| 601 } | |
| 602 | |
| 603 void WebRtcAudioCapturer::SetCapturerSourceForTesting( | 569 void WebRtcAudioCapturer::SetCapturerSourceForTesting( |
| 604 const scoped_refptr<media::AudioCapturerSource>& source, | 570 const scoped_refptr<media::AudioCapturerSource>& source, |
| 605 media::AudioParameters params) { | 571 media::AudioParameters params) { |
| 606 // Create a new audio stream as source which uses the new source. | 572 // Create a new audio stream as source which uses the new source. |
| 607 SetCapturerSource(source, params.channel_layout(), | 573 SetCapturerSource(source, params.channel_layout(), |
| 608 static_cast<float>(params.sample_rate())); | 574 static_cast<float>(params.sample_rate())); |
| 609 } | 575 } |
| 610 | 576 |
| 611 } // namespace content | 577 } // namespace content |
| OLD | NEW |