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 |