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/webrtc_audio_device_impl.h" | 5 #include "content/renderer/media/webrtc_audio_device_impl.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
9 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
10 #include "base/win/windows_version.h" | 10 #include "base/win/windows_version.h" |
11 #include "content/renderer/media/media_stream_audio_processor.h" | 11 #include "content/renderer/media/media_stream_audio_processor.h" |
12 #include "content/renderer/media/webrtc_audio_capturer.h" | 12 #include "content/renderer/media/webrtc_audio_capturer.h" |
13 #include "content/renderer/media/webrtc_audio_renderer.h" | 13 #include "content/renderer/media/webrtc_audio_renderer.h" |
14 #include "content/renderer/render_thread_impl.h" | 14 #include "content/renderer/render_thread_impl.h" |
15 #include "media/audio/audio_parameters.h" | 15 #include "media/audio/audio_parameters.h" |
16 #include "media/audio/sample_rates.h" | 16 #include "media/audio/sample_rates.h" |
17 | 17 |
18 using media::AudioParameters; | 18 using media::AudioParameters; |
19 using media::ChannelLayout; | 19 using media::ChannelLayout; |
20 | 20 |
21 namespace { | |
22 int g_capturer_id_counter = 0; | |
no longer working on chromium
2014/06/16 18:30:55
why? can't it be a member instead?
Henrik Grunell
2014/06/17 20:21:41
Right, it can. Done.
| |
23 } | |
24 | |
21 namespace content { | 25 namespace content { |
22 | 26 |
23 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl() | 27 WebRtcAudioDeviceImpl::WebRtcAudioDeviceImpl() |
24 : ref_count_(0), | 28 : ref_count_(0), |
25 audio_transport_callback_(NULL), | 29 audio_transport_callback_(NULL), |
26 input_delay_ms_(0), | 30 input_delay_ms_(0), |
27 output_delay_ms_(0), | 31 output_delay_ms_(0), |
28 initialized_(false), | 32 initialized_(false), |
29 playing_(false), | 33 playing_(false), |
30 recording_(false), | 34 recording_(false), |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 DCHECK(thread_checker_.CalledOnValidThread()); | 224 DCHECK(thread_checker_.CalledOnValidThread()); |
221 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL); | 225 DCHECK_EQ(audio_transport_callback_ == NULL, audio_callback != NULL); |
222 audio_transport_callback_ = audio_callback; | 226 audio_transport_callback_ = audio_callback; |
223 return 0; | 227 return 0; |
224 } | 228 } |
225 | 229 |
226 int32_t WebRtcAudioDeviceImpl::Init() { | 230 int32_t WebRtcAudioDeviceImpl::Init() { |
227 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()"; | 231 DVLOG(1) << "WebRtcAudioDeviceImpl::Init()"; |
228 DCHECK(thread_checker_.CalledOnValidThread()); | 232 DCHECK(thread_checker_.CalledOnValidThread()); |
229 | 233 |
234 if (MediaStreamAudioProcessor::IsAudioTrackProcessingEnabled()) { | |
no longer working on chromium
2014/06/16 18:30:55
WebRtcAudioDeviceImpl is not the right place for a
Henrik Grunell
2014/06/17 20:21:41
After discussing offline I understand that this is
| |
235 aec_dump_message_filter_ = AecDumpMessageFilter::Get(); | |
236 DCHECK(aec_dump_message_filter_); | |
no longer working on chromium
2014/06/16 18:30:55
you don't need this DCHECK(), the following line w
Henrik Grunell
2014/06/17 20:21:41
Done.
| |
237 aec_dump_message_filter_->SetObserver(this); | |
238 for (CapturerMap::const_iterator iter = capturers_.begin(); | |
239 iter != capturers_.end(); ++iter) { | |
240 RegisterAecDumpForId(iter->first); | |
no longer working on chromium
2014/06/16 18:30:55
indentation.
Henrik Grunell
2014/06/17 20:21:41
Done.
| |
241 } | |
242 } | |
243 | |
230 // We need to return a success to continue the initialization of WebRtc VoE | 244 // We need to return a success to continue the initialization of WebRtc VoE |
231 // because failure on the capturer_ initialization should not prevent WebRTC | 245 // because failure on the capturer_ initialization should not prevent WebRTC |
232 // from working. See issue http://crbug.com/144421 for details. | 246 // from working. See issue http://crbug.com/144421 for details. |
233 initialized_ = true; | 247 initialized_ = true; |
234 | 248 |
235 return 0; | 249 return 0; |
236 } | 250 } |
237 | 251 |
238 int32_t WebRtcAudioDeviceImpl::Terminate() { | 252 int32_t WebRtcAudioDeviceImpl::Terminate() { |
239 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()"; | 253 DVLOG(1) << "WebRtcAudioDeviceImpl::Terminate()"; |
240 DCHECK(thread_checker_.CalledOnValidThread()); | 254 DCHECK(thread_checker_.CalledOnValidThread()); |
241 | 255 |
242 // Calling Terminate() multiple times in a row is OK. | 256 // Calling Terminate() multiple times in a row is OK. |
243 if (!initialized_) | 257 if (!initialized_) |
244 return 0; | 258 return 0; |
245 | 259 |
246 StopRecording(); | 260 StopRecording(); |
247 StopPlayout(); | 261 StopPlayout(); |
248 | 262 |
249 DCHECK(!renderer_.get() || !renderer_->IsStarted()) | 263 DCHECK(!renderer_.get() || !renderer_->IsStarted()) |
250 << "The shared audio renderer shouldn't be running"; | 264 << "The shared audio renderer shouldn't be running"; |
251 | 265 |
266 if (aec_dump_message_filter_) { | |
267 aec_dump_message_filter_->SetObserver(NULL); | |
no longer working on chromium
2014/06/16 18:30:55
if you have more than 1 tab using webrtc, this Set
Henrik Grunell
2014/06/17 20:21:41
This is changed now. MSAP is a delegate instead.
| |
268 aec_dump_message_filter_ = NULL; | |
269 } | |
270 | |
252 DisableAecDump(); | 271 DisableAecDump(); |
253 | 272 |
254 // Stop all the capturers to ensure no further OnData() and | 273 // Stop all the capturers to ensure no further OnData() and |
255 // RemoveAudioCapturer() callback. | 274 // RemoveAudioCapturer() callback. |
256 // Cache the capturers in a local list since WebRtcAudioCapturer::Stop() | 275 // Cache the capturers in a local list since WebRtcAudioCapturer::Stop() |
257 // will trigger RemoveAudioCapturer() callback. | 276 // will trigger RemoveAudioCapturer() callback. |
258 CapturerList capturers; | 277 CapturerMap capturers; |
259 capturers.swap(capturers_); | 278 capturers.swap(capturers_); |
260 for (CapturerList::const_iterator iter = capturers.begin(); | 279 for (CapturerMap::const_iterator iter = capturers.begin(); |
261 iter != capturers.end(); ++iter) { | 280 iter != capturers.end(); ++iter) { |
262 (*iter)->Stop(); | 281 iter->second->Stop(); |
263 } | 282 } |
264 | 283 |
265 initialized_ = false; | 284 initialized_ = false; |
266 return 0; | 285 return 0; |
267 } | 286 } |
268 | 287 |
269 bool WebRtcAudioDeviceImpl::Initialized() const { | 288 bool WebRtcAudioDeviceImpl::Initialized() const { |
270 return initialized_; | 289 return initialized_; |
271 } | 290 } |
272 | 291 |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
443 capturer->source_audio_parameters().sample_rate()); | 462 capturer->source_audio_parameters().sample_rate()); |
444 return 0; | 463 return 0; |
445 } | 464 } |
446 | 465 |
447 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate( | 466 int32_t WebRtcAudioDeviceImpl::PlayoutSampleRate( |
448 uint32_t* sample_rate) const { | 467 uint32_t* sample_rate) const { |
449 *sample_rate = renderer_ ? renderer_->sample_rate() : 0; | 468 *sample_rate = renderer_ ? renderer_->sample_rate() : 0; |
450 return 0; | 469 return 0; |
451 } | 470 } |
452 | 471 |
472 void WebRtcAudioDeviceImpl::OnAecDumpFile( | |
473 int id, | |
474 const IPC::PlatformFileForTransit& file_handle) { | |
475 DCHECK(thread_checker_.CalledOnValidThread()); | |
476 base::File file = IPC::PlatformFileForTransitToFile(file_handle); | |
477 DCHECK(file.IsValid()); | |
478 | |
479 CapturerMap::iterator iter = capturers_.find(id); | |
480 if (iter != capturers_.end()) { | |
481 iter->second->StartAecDump(file.Pass()); | |
482 } else { | |
483 // The capturer has been removed. | |
484 file.Close(); | |
485 } | |
486 } | |
487 | |
488 void WebRtcAudioDeviceImpl::OnDisableAecDump() { | |
489 DCHECK(thread_checker_.CalledOnValidThread()); | |
490 DisableAecDump(); | |
491 } | |
492 | |
493 void WebRtcAudioDeviceImpl::OnIpcClosed() { | |
494 DCHECK(thread_checker_.CalledOnValidThread()); | |
495 aec_dump_message_filter_ = NULL; | |
496 } | |
497 | |
453 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) { | 498 bool WebRtcAudioDeviceImpl::SetAudioRenderer(WebRtcAudioRenderer* renderer) { |
454 DCHECK(thread_checker_.CalledOnValidThread()); | 499 DCHECK(thread_checker_.CalledOnValidThread()); |
455 DCHECK(renderer); | 500 DCHECK(renderer); |
456 | 501 |
457 base::AutoLock auto_lock(lock_); | 502 base::AutoLock auto_lock(lock_); |
458 if (renderer_.get()) | 503 if (renderer_.get()) |
459 return false; | 504 return false; |
460 | 505 |
461 if (!renderer->Initialize(this)) | 506 if (!renderer->Initialize(this)) |
462 return false; | 507 return false; |
463 | 508 |
464 renderer_ = renderer; | 509 renderer_ = renderer; |
465 return true; | 510 return true; |
466 } | 511 } |
467 | 512 |
468 void WebRtcAudioDeviceImpl::AddAudioCapturer( | 513 void WebRtcAudioDeviceImpl::AddAudioCapturer( |
469 const scoped_refptr<WebRtcAudioCapturer>& capturer) { | 514 const scoped_refptr<WebRtcAudioCapturer>& capturer) { |
470 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()"; | 515 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()"; |
471 DCHECK(thread_checker_.CalledOnValidThread()); | 516 DCHECK(thread_checker_.CalledOnValidThread()); |
472 DCHECK(capturer.get()); | 517 DCHECK(capturer.get()); |
473 DCHECK(!capturer->device_id().empty()); | 518 DCHECK(!capturer->device_id().empty()); |
519 | |
520 int id = g_capturer_id_counter++; | |
Tom Sepez
2014/06/16 17:33:18
why is it OK to increment this outside the lock?
Henrik Grunell
2014/06/17 20:21:41
This has been removed, ids are handled in the mess
| |
474 { | 521 { |
475 base::AutoLock auto_lock(lock_); | 522 base::AutoLock auto_lock(lock_); |
476 DCHECK(std::find(capturers_.begin(), capturers_.end(), capturer) == | 523 DCHECK(capturers_.find(id) == capturers_.end()); |
477 capturers_.end()); | 524 for (CapturerMap::const_iterator iter = capturers_.begin(); |
478 capturers_.push_back(capturer); | 525 iter != capturers_.end(); ++iter) { |
526 DCHECK(capturer != iter->second); | |
527 } | |
528 capturers_[id] = capturer; | |
479 } | 529 } |
480 | 530 RegisterAecDumpForId(id); |
481 // Start the Aec dump if the Aec dump has been enabled and has not been | |
482 // started. | |
483 if (aec_dump_file_.IsValid()) | |
484 MaybeStartAecDump(); | |
485 } | 531 } |
486 | 532 |
487 void WebRtcAudioDeviceImpl::RemoveAudioCapturer( | 533 void WebRtcAudioDeviceImpl::RemoveAudioCapturer( |
488 const scoped_refptr<WebRtcAudioCapturer>& capturer) { | 534 const scoped_refptr<WebRtcAudioCapturer>& capturer) { |
489 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()"; | 535 DVLOG(1) << "WebRtcAudioDeviceImpl::AddAudioCapturer()"; |
490 DCHECK(thread_checker_.CalledOnValidThread()); | 536 DCHECK(thread_checker_.CalledOnValidThread()); |
491 DCHECK(capturer.get()); | 537 DCHECK(capturer.get()); |
492 base::AutoLock auto_lock(lock_); | 538 |
493 capturers_.remove(capturer); | 539 int id = -1; |
540 { | |
541 base::AutoLock auto_lock(lock_); | |
542 for (CapturerMap::iterator iter = capturers_.begin(); | |
543 iter != capturers_.end(); ++iter) { | |
544 if (iter->second == capturer) { | |
545 id = iter->first; | |
546 capturers_.erase(iter); | |
547 break; | |
548 } | |
549 } | |
550 } | |
551 DCHECK_GE(id, 0); | |
552 | |
553 if (aec_dump_message_filter_) { | |
554 aec_dump_message_filter_->io_message_loop()->PostTask( | |
555 FROM_HERE, | |
556 base::Bind( | |
557 &AecDumpMessageFilter::UnregisterAecDumpConsumer, | |
558 aec_dump_message_filter_, | |
559 id)); | |
560 } | |
494 } | 561 } |
495 | 562 |
496 scoped_refptr<WebRtcAudioCapturer> | 563 scoped_refptr<WebRtcAudioCapturer> |
497 WebRtcAudioDeviceImpl::GetDefaultCapturer() const { | 564 WebRtcAudioDeviceImpl::GetDefaultCapturer() const { |
498 base::AutoLock auto_lock(lock_); | 565 base::AutoLock auto_lock(lock_); |
499 // Use the last |capturer| which is from the latest getUserMedia call as | 566 // Use the last |capturer| which is from the latest getUserMedia call as |
500 // the default capture device. | 567 // the default capture device. The last capturer will have the largest key, |
501 return capturers_.empty() ? NULL : capturers_.back(); | 568 // so it will be last entry in the map. |
569 return capturers_.empty() ? NULL : capturers_.rbegin()->second; | |
502 } | 570 } |
503 | 571 |
504 void WebRtcAudioDeviceImpl::AddPlayoutSink( | 572 void WebRtcAudioDeviceImpl::AddPlayoutSink( |
505 WebRtcPlayoutDataSource::Sink* sink) { | 573 WebRtcPlayoutDataSource::Sink* sink) { |
506 DCHECK(thread_checker_.CalledOnValidThread()); | 574 DCHECK(thread_checker_.CalledOnValidThread()); |
507 DCHECK(sink); | 575 DCHECK(sink); |
508 base::AutoLock auto_lock(lock_); | 576 base::AutoLock auto_lock(lock_); |
509 DCHECK(std::find(playout_sinks_.begin(), playout_sinks_.end(), sink) == | 577 DCHECK(std::find(playout_sinks_.begin(), playout_sinks_.end(), sink) == |
510 playout_sinks_.end()); | 578 playout_sinks_.end()); |
511 playout_sinks_.push_back(sink); | 579 playout_sinks_.push_back(sink); |
(...skipping 14 matching lines...) Expand all Loading... | |
526 DCHECK(thread_checker_.CalledOnValidThread()); | 594 DCHECK(thread_checker_.CalledOnValidThread()); |
527 // If there is no capturer or there are more than one open capture devices, | 595 // If there is no capturer or there are more than one open capture devices, |
528 // return false. | 596 // return false. |
529 if (capturers_.empty() || capturers_.size() > 1) | 597 if (capturers_.empty() || capturers_.size() > 1) |
530 return false; | 598 return false; |
531 | 599 |
532 return GetDefaultCapturer()->GetPairedOutputParameters( | 600 return GetDefaultCapturer()->GetPairedOutputParameters( |
533 session_id, output_sample_rate, output_frames_per_buffer); | 601 session_id, output_sample_rate, output_frames_per_buffer); |
534 } | 602 } |
535 | 603 |
536 void WebRtcAudioDeviceImpl::EnableAecDump(base::File aec_dump_file) { | 604 void WebRtcAudioDeviceImpl::RegisterAecDumpForId(int id) { |
537 DCHECK(thread_checker_.CalledOnValidThread()); | 605 DCHECK(thread_checker_.CalledOnValidThread()); |
538 DCHECK(aec_dump_file.IsValid()); | 606 if (aec_dump_message_filter_) { |
539 | 607 aec_dump_message_filter_->io_message_loop()->PostTask( |
540 // Close the previous AEC dump file description if it has not been consumed. | 608 FROM_HERE, |
541 // This can happen if no getUserMedia has been made yet. | 609 base::Bind( |
542 // TODO(xians): DCHECK(!aec_dump_file_.IsValid()) after the browser | 610 &AecDumpMessageFilter::RegisterAecDumpConsumer, |
543 // guarantees it won't call EnableAecDump() more than once in a row. | 611 aec_dump_message_filter_, |
544 if (aec_dump_file_.IsValid()) | 612 id)); |
545 aec_dump_file_.Close(); | 613 } |
546 | |
547 aec_dump_file_ = aec_dump_file.Pass(); | |
548 MaybeStartAecDump(); | |
549 } | 614 } |
550 | 615 |
551 void WebRtcAudioDeviceImpl::DisableAecDump() { | 616 void WebRtcAudioDeviceImpl::DisableAecDump() { |
552 DCHECK(thread_checker_.CalledOnValidThread()); | 617 DCHECK(thread_checker_.CalledOnValidThread()); |
553 // Simply invalidate the |aec_dump_file_| if we have not pass the ownership | 618 for (CapturerMap::const_iterator iter = capturers_.begin(); |
554 // to WebRtc. | |
555 if (aec_dump_file_.IsValid()) { | |
556 aec_dump_file_.Close(); | |
557 return; | |
558 } | |
559 | |
560 // We might have call StartAecDump() on one of the capturer. Loop | |
561 // through all the capturers and call StopAecDump() on each of them. | |
562 for (CapturerList::const_iterator iter = capturers_.begin(); | |
563 iter != capturers_.end(); ++iter) { | 619 iter != capturers_.end(); ++iter) { |
564 (*iter)->StopAecDump(); | 620 iter->second->StopAecDump(); |
565 } | 621 } |
566 } | 622 } |
567 | 623 |
568 void WebRtcAudioDeviceImpl::MaybeStartAecDump() { | |
569 DCHECK(thread_checker_.CalledOnValidThread()); | |
570 DCHECK(aec_dump_file_.IsValid()); | |
571 | |
572 // Start the Aec dump on the current default capturer. | |
573 scoped_refptr<WebRtcAudioCapturer> default_capturer(GetDefaultCapturer()); | |
574 if (!default_capturer) | |
575 return; | |
576 | |
577 default_capturer->StartAecDump(aec_dump_file_.Pass()); | |
578 } | |
579 | |
580 } // namespace content | 624 } // namespace content |
OLD | NEW |