Chromium Code Reviews| 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/browser/renderer_host/media/audio_renderer_host.h" | 5 #include "content/browser/renderer_host/media/audio_renderer_host.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "base/memory/shared_memory.h" | 10 #include "base/memory/shared_memory.h" |
| 11 #include "base/metrics/histogram.h" | 11 #include "base/metrics/histogram.h" |
| 12 #include "base/process/process.h" | 12 #include "base/process/process.h" |
| 13 #include "content/browser/browser_main_loop.h" | 13 #include "content/browser/browser_main_loop.h" |
| 14 #include "content/browser/child_process_security_policy_impl.h" | |
| 14 #include "content/browser/loader/resource_dispatcher_host_impl.h" | 15 #include "content/browser/loader/resource_dispatcher_host_impl.h" |
| 15 #include "content/browser/media/audio_stream_monitor.h" | 16 #include "content/browser/media/audio_stream_monitor.h" |
| 16 #include "content/browser/media/capture/audio_mirroring_manager.h" | 17 #include "content/browser/media/capture/audio_mirroring_manager.h" |
| 17 #include "content/browser/media/media_internals.h" | 18 #include "content/browser/media/media_internals.h" |
| 18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" | 19 #include "content/browser/renderer_host/media/audio_input_device_manager.h" |
| 19 #include "content/browser/renderer_host/media/audio_sync_reader.h" | 20 #include "content/browser/renderer_host/media/audio_sync_reader.h" |
| 20 #include "content/browser/renderer_host/media/media_stream_manager.h" | 21 #include "content/browser/renderer_host/media/media_stream_manager.h" |
| 22 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h" | |
| 21 #include "content/browser/renderer_host/render_widget_host_impl.h" | 23 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 22 #include "content/common/media/audio_messages.h" | 24 #include "content/common/media/audio_messages.h" |
| 23 #include "content/public/browser/content_browser_client.h" | 25 #include "content/public/browser/content_browser_client.h" |
| 26 #include "content/public/browser/media_device_id.h" | |
| 24 #include "content/public/browser/media_observer.h" | 27 #include "content/public/browser/media_observer.h" |
| 25 #include "content/public/browser/render_frame_host.h" | 28 #include "content/public/browser/render_frame_host.h" |
| 26 #include "content/public/browser/render_view_host.h" | 29 #include "content/public/browser/render_view_host.h" |
| 27 #include "content/public/common/content_switches.h" | 30 #include "content/public/common/content_switches.h" |
| 31 #include "media/audio/audio_device_name.h" | |
| 28 #include "media/audio/audio_manager_base.h" | 32 #include "media/audio/audio_manager_base.h" |
| 29 #include "media/base/audio_bus.h" | 33 #include "media/base/audio_bus.h" |
| 30 #include "media/base/limits.h" | 34 #include "media/base/limits.h" |
| 31 | 35 |
| 32 using media::AudioBus; | 36 using media::AudioBus; |
| 33 using media::AudioManager; | 37 using media::AudioManager; |
| 34 | 38 |
| 35 namespace content { | 39 namespace content { |
| 36 | 40 |
| 37 namespace { | 41 namespace { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 AudioRendererHost::AudioEntry::~AudioEntry() {} | 143 AudioRendererHost::AudioEntry::~AudioEntry() {} |
| 140 | 144 |
| 141 /////////////////////////////////////////////////////////////////////////////// | 145 /////////////////////////////////////////////////////////////////////////////// |
| 142 // AudioRendererHost implementations. | 146 // AudioRendererHost implementations. |
| 143 | 147 |
| 144 AudioRendererHost::AudioRendererHost( | 148 AudioRendererHost::AudioRendererHost( |
| 145 int render_process_id, | 149 int render_process_id, |
| 146 media::AudioManager* audio_manager, | 150 media::AudioManager* audio_manager, |
| 147 AudioMirroringManager* mirroring_manager, | 151 AudioMirroringManager* mirroring_manager, |
| 148 MediaInternals* media_internals, | 152 MediaInternals* media_internals, |
| 149 MediaStreamManager* media_stream_manager) | 153 MediaStreamManager* media_stream_manager, |
| 154 const ResourceContext::SaltCallback& salt_callback) | |
| 150 : BrowserMessageFilter(AudioMsgStart), | 155 : BrowserMessageFilter(AudioMsgStart), |
| 151 render_process_id_(render_process_id), | 156 render_process_id_(render_process_id), |
| 152 audio_manager_(audio_manager), | 157 audio_manager_(audio_manager), |
| 153 mirroring_manager_(mirroring_manager), | 158 mirroring_manager_(mirroring_manager), |
| 154 audio_log_(media_internals->CreateAudioLog( | 159 audio_log_(media_internals->CreateAudioLog( |
| 155 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), | 160 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), |
| 156 media_stream_manager_(media_stream_manager), | 161 media_stream_manager_(media_stream_manager), |
| 157 num_playing_streams_(0) { | 162 num_playing_streams_(0), |
| 163 salt_callback_(salt_callback) { | |
| 158 DCHECK(audio_manager_); | 164 DCHECK(audio_manager_); |
| 159 DCHECK(media_stream_manager_); | 165 DCHECK(media_stream_manager_); |
| 160 } | 166 } |
| 161 | 167 |
| 162 AudioRendererHost::~AudioRendererHost() { | 168 AudioRendererHost::~AudioRendererHost() { |
| 163 DCHECK(audio_entries_.empty()); | 169 DCHECK(audio_entries_.empty()); |
| 164 } | 170 } |
| 165 | 171 |
| 166 void AudioRendererHost::GetOutputControllers( | 172 void AudioRendererHost::GetOutputControllers( |
| 167 const RenderProcessHost::GetAudioOutputControllersCallback& | 173 const RenderProcessHost::GetAudioOutputControllersCallback& |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 303 /////////////////////////////////////////////////////////////////////////////// | 309 /////////////////////////////////////////////////////////////////////////////// |
| 304 // IPC Messages handler | 310 // IPC Messages handler |
| 305 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { | 311 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { |
| 306 bool handled = true; | 312 bool handled = true; |
| 307 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) | 313 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) |
| 308 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) | 314 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) |
| 309 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) | 315 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) |
| 310 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) | 316 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) |
| 311 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) | 317 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) |
| 312 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) | 318 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) |
| 319 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice) | |
| 313 IPC_MESSAGE_UNHANDLED(handled = false) | 320 IPC_MESSAGE_UNHANDLED(handled = false) |
| 314 IPC_END_MESSAGE_MAP() | 321 IPC_END_MESSAGE_MAP() |
| 315 | 322 |
| 316 return handled; | 323 return handled; |
| 317 } | 324 } |
| 318 | 325 |
| 319 void AudioRendererHost::OnCreateStream(int stream_id, | 326 void AudioRendererHost::OnCreateStream(int stream_id, |
| 320 int render_frame_id, | 327 int render_frame_id, |
| 321 int session_id, | 328 int session_id, |
| 322 const media::AudioParameters& params) { | 329 const media::AudioParameters& params) { |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 return; | 422 return; |
| 416 } | 423 } |
| 417 | 424 |
| 418 // Make sure the volume is valid. | 425 // Make sure the volume is valid. |
| 419 if (volume < 0 || volume > 1.0) | 426 if (volume < 0 || volume > 1.0) |
| 420 return; | 427 return; |
| 421 entry->controller()->SetVolume(volume); | 428 entry->controller()->SetVolume(volume); |
| 422 audio_log_->OnSetVolume(stream_id, volume); | 429 audio_log_->OnSetVolume(stream_id, volume); |
| 423 } | 430 } |
| 424 | 431 |
| 432 void AudioRendererHost::OnSwitchOutputDevice(int stream_id, | |
| 433 int render_frame_id, | |
| 434 const std::string& device_id, | |
| 435 const GURL& security_origin, | |
| 436 int request_id) { | |
| 437 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 438 DVLOG(1) << "AudioRendererHost@" << this | |
| 439 << "::OnSwitchOutputDevice(stream_id=" << stream_id | |
| 440 << ", render_frame_id=" << render_frame_id | |
| 441 << ", device_id=" << device_id | |
| 442 << ", security_origin=" << security_origin | |
| 443 << ", request_id=" << request_id << ")"; | |
| 444 if (!IsURLAllowed(security_origin)) { | |
| 445 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 446 stream_id, request_id, media::AudioOutputIPCDelegate::kSecurityError)); | |
| 447 return; | |
| 448 } | |
| 449 | |
| 450 if (device_id.empty()) { | |
| 451 DVLOG(1) << __FUNCTION__ << ": default output device requested. " | |
| 452 << "No permissions check or device translation/validation needed."; | |
| 453 DoSwitchOutputDevice(stream_id, device_id, request_id); | |
| 454 } else { | |
| 455 // Check that MediaStream device permissions have been granted, | |
| 456 // hence the use of a MediaStreamUIProxy. | |
| 457 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create(); | |
| 458 | |
| 459 // Use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT | |
|
miu
2015/06/09 19:49:25
This sounds like a TODO item. Is the behavior sup
Guido Urdaneta
2015/06/10 09:44:55
Done.
| |
| 460 // because MediaStreamUIProxy::CheckAccess does not currently support | |
| 461 // MEDIA_DEVICE_AUDIO_OUTPUT. | |
| 462 ui_proxy->CheckAccess( | |
| 463 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, | |
| 464 render_process_id_, render_frame_id, | |
| 465 base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this, | |
| 466 base::Passed(&ui_proxy), stream_id, device_id, | |
| 467 security_origin, render_frame_id, request_id)); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 void AudioRendererHost::OutputDeviceAccessChecked( | |
| 472 scoped_ptr<MediaStreamUIProxy> ui_proxy, | |
| 473 int stream_id, | |
| 474 const std::string& device_id, | |
| 475 const GURL& security_origin, | |
| 476 int render_frame_id, | |
| 477 int request_id, | |
| 478 bool have_access) { | |
| 479 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 480 DVLOG(1) << __FUNCTION__; | |
| 481 if (!have_access) { | |
| 482 DVLOG(0) << __FUNCTION__ | |
| 483 << ": Have no access to media devices. Not switching device."; | |
| 484 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 485 stream_id, request_id, media::AudioOutputIPCDelegate::kSecurityError)); | |
| 486 return; | |
| 487 } | |
| 488 | |
| 489 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner = | |
| 490 AudioManager::Get()->GetWorkerTaskRunner(); | |
| 491 audio_worker_runner->PostTask( | |
| 492 FROM_HERE, | |
| 493 base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this, | |
| 494 stream_id, device_id, security_origin, request_id)); | |
| 495 } | |
| 496 | |
| 497 void AudioRendererHost::StartTranslateOutputDeviceName( | |
| 498 int stream_id, | |
| 499 const std::string& device_id, | |
| 500 const GURL& security_origin, | |
| 501 int request_id) { | |
| 502 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread()); | |
| 503 DCHECK(!device_id.empty()); | |
| 504 DVLOG(1) << __FUNCTION__; | |
| 505 | |
| 506 media::AudioDeviceNames* device_names = new media::AudioDeviceNames; | |
|
tommi (sloooow) - chröme
2015/06/09 20:27:48
nit: use ()
Guido Urdaneta
2015/06/10 09:44:55
Done.
| |
| 507 AudioManager::Get()->GetAudioOutputDeviceNames(device_names); | |
| 508 | |
| 509 BrowserThread::PostTask( | |
| 510 BrowserThread::IO, FROM_HERE, | |
| 511 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this, | |
| 512 stream_id, device_id, security_origin, request_id, | |
| 513 base::Owned(device_names))); | |
| 514 } | |
| 515 | |
| 516 void AudioRendererHost::FinishTranslateOutputDeviceName( | |
| 517 int stream_id, | |
| 518 const std::string& device_id, | |
| 519 const GURL& security_origin, | |
| 520 int request_id, | |
| 521 media::AudioDeviceNames* device_names) { | |
| 522 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 523 DCHECK(!device_id.empty()); | |
| 524 DVLOG(1) << __FUNCTION__; | |
| 525 | |
| 526 std::string raw_device_id = ""; | |
|
tommi (sloooow) - chröme
2015/06/09 20:27:48
nit: initialization to "" not necessary...(or?)
Guido Urdaneta
2015/06/10 09:44:55
Done.
| |
| 527 // Process the enumeration here because |salt_callback_| can run | |
| 528 // only on the IO thread | |
| 529 for (const auto& device_name : *device_names) { | |
| 530 const std::string candidate_device_id = content::GetHMACForMediaDeviceID( | |
| 531 salt_callback_, security_origin, device_name.unique_id); | |
| 532 if (candidate_device_id == device_id) { | |
| 533 DVLOG(1) << "Requested device " << device_name.unique_id << " - " | |
| 534 << device_name.device_name; | |
| 535 raw_device_id = device_name.unique_id; | |
| 536 } | |
| 537 } | |
| 538 | |
| 539 if (raw_device_id.empty()) { | |
| 540 DVLOG(1) << "Requested device " << device_id << " could not be found."; | |
| 541 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 542 stream_id, request_id, media::AudioOutputIPCDelegate::kNotFoundError)); | |
| 543 return; | |
| 544 } | |
| 545 | |
| 546 DoSwitchOutputDevice(stream_id, raw_device_id, request_id); | |
| 547 } | |
| 548 | |
| 549 void AudioRendererHost::DoSwitchOutputDevice(int stream_id, | |
| 550 const std::string& raw_device_id, | |
| 551 int request_id) { | |
| 552 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 553 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", " | |
| 554 << request_id << ")"; | |
| 555 AudioEntry* entry = LookupById(stream_id); | |
| 556 if (!entry) { | |
| 557 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 558 stream_id, request_id, media::AudioOutputIPCDelegate::kOtherError)); | |
|
miu
2015/06/09 19:49:25
This is the only place kOtherError is provided. S
Guido Urdaneta
2015/06/10 09:44:55
Done.
| |
| 559 return; | |
| 560 } | |
| 561 | |
| 562 entry->controller()->SwitchOutputDevice( | |
| 563 raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched, | |
| 564 this, stream_id, request_id)); | |
| 565 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id); | |
| 566 } | |
| 567 | |
| 568 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) { | |
| 569 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 570 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")"; | |
| 571 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 572 stream_id, request_id, media::AudioOutputIPCDelegate::kSuccess)); | |
| 573 } | |
| 574 | |
| 425 void AudioRendererHost::SendErrorMessage(int stream_id) { | 575 void AudioRendererHost::SendErrorMessage(int stream_id) { |
| 426 Send(new AudioMsg_NotifyStreamStateChanged( | 576 Send(new AudioMsg_NotifyStreamStateChanged( |
| 427 stream_id, media::AudioOutputIPCDelegate::kError)); | 577 stream_id, media::AudioOutputIPCDelegate::kError)); |
| 428 } | 578 } |
| 429 | 579 |
| 430 void AudioRendererHost::OnCloseStream(int stream_id) { | 580 void AudioRendererHost::OnCloseStream(int stream_id) { |
| 431 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 581 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 432 | 582 |
| 433 // Prevent oustanding callbacks from attempting to close/delete the same | 583 // Prevent oustanding callbacks from attempting to close/delete the same |
| 434 // AudioEntry twice. | 584 // AudioEntry twice. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 512 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 662 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); |
| 513 it != audio_entries_.end(); | 663 it != audio_entries_.end(); |
| 514 ++it) { | 664 ++it) { |
| 515 AudioEntry* entry = it->second; | 665 AudioEntry* entry = it->second; |
| 516 if (entry->render_frame_id() == render_frame_id && entry->playing()) | 666 if (entry->render_frame_id() == render_frame_id && entry->playing()) |
| 517 return true; | 667 return true; |
| 518 } | 668 } |
| 519 return false; | 669 return false; |
| 520 } | 670 } |
| 521 | 671 |
| 672 bool AudioRendererHost::IsURLAllowed(const GURL& url) { | |
| 673 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( | |
| 674 render_process_id_, url)) { | |
| 675 LOG(ERROR) << "MSDH: Renderer requested a URL it's not allowed to use."; | |
| 676 return false; | |
| 677 } | |
| 678 return true; | |
| 679 } | |
| 680 | |
| 522 } // namespace content | 681 } // namespace content |
| OLD | NEW |