Chromium Code Reviews| 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 |