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)) { | |
|
ncarter (slow)
2015/06/10 18:10:48
When a renderer steps out of bounds like this, the
Guido Urdaneta
2015/06/11 00:51:57
Done.
| |
| 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 | |
| 460 // because MediaStreamUIProxy::CheckAccess does not currently support | |
| 461 // MEDIA_DEVICE_AUDIO_OUTPUT. | |
| 462 // TODO(guidou): Change to MEDIA_DEVICE_AUDIO_OUTPUT when support becomes | |
| 463 // available. http://crbug.com/498675 | |
| 464 ui_proxy->CheckAccess( | |
| 465 security_origin, MEDIA_DEVICE_AUDIO_CAPTURE, | |
| 466 render_process_id_, render_frame_id, | |
| 467 base::Bind(&AudioRendererHost::OutputDeviceAccessChecked, this, | |
| 468 base::Passed(&ui_proxy), stream_id, device_id, | |
| 469 security_origin, render_frame_id, request_id)); | |
| 470 } | |
| 471 } | |
| 472 | |
| 473 void AudioRendererHost::OutputDeviceAccessChecked( | |
| 474 scoped_ptr<MediaStreamUIProxy> ui_proxy, | |
| 475 int stream_id, | |
| 476 const std::string& device_id, | |
| 477 const GURL& security_origin, | |
| 478 int render_frame_id, | |
| 479 int request_id, | |
| 480 bool have_access) { | |
| 481 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 482 DVLOG(1) << __FUNCTION__; | |
| 483 if (!have_access) { | |
| 484 DVLOG(0) << __FUNCTION__ | |
| 485 << ": Have no access to media devices. Not switching device."; | |
| 486 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 487 stream_id, request_id, media::AudioOutputIPCDelegate::kSecurityError)); | |
|
ncarter (slow)
2015/06/10 18:10:47
Get rid of kSecurityError, and use bad_message.
I
Guido Urdaneta
2015/06/11 00:51:57
In this case, we have to communicate the problem b
| |
| 488 return; | |
| 489 } | |
| 490 | |
| 491 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner = | |
| 492 AudioManager::Get()->GetWorkerTaskRunner(); | |
| 493 audio_worker_runner->PostTask( | |
| 494 FROM_HERE, | |
| 495 base::Bind(&AudioRendererHost::StartTranslateOutputDeviceName, this, | |
| 496 stream_id, device_id, security_origin, request_id)); | |
| 497 } | |
| 498 | |
| 499 void AudioRendererHost::StartTranslateOutputDeviceName( | |
| 500 int stream_id, | |
| 501 const std::string& device_id, | |
| 502 const GURL& security_origin, | |
| 503 int request_id) { | |
| 504 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread()); | |
| 505 DCHECK(!device_id.empty()); | |
| 506 DVLOG(1) << __FUNCTION__; | |
| 507 | |
| 508 media::AudioDeviceNames* device_names(new media::AudioDeviceNames); | |
| 509 AudioManager::Get()->GetAudioOutputDeviceNames(device_names); | |
| 510 | |
| 511 BrowserThread::PostTask( | |
| 512 BrowserThread::IO, FROM_HERE, | |
| 513 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName, this, | |
| 514 stream_id, device_id, security_origin, request_id, | |
| 515 base::Owned(device_names))); | |
| 516 } | |
| 517 | |
| 518 void AudioRendererHost::FinishTranslateOutputDeviceName( | |
| 519 int stream_id, | |
| 520 const std::string& device_id, | |
| 521 const GURL& security_origin, | |
| 522 int request_id, | |
| 523 media::AudioDeviceNames* device_names) { | |
| 524 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 525 DCHECK(!device_id.empty()); | |
| 526 DVLOG(1) << __FUNCTION__; | |
| 527 | |
| 528 std::string raw_device_id; | |
| 529 // Process the enumeration here because |salt_callback_| can run | |
| 530 // only on the IO thread | |
| 531 for (const auto& device_name : *device_names) { | |
| 532 const std::string candidate_device_id = content::GetHMACForMediaDeviceID( | |
| 533 salt_callback_, security_origin, device_name.unique_id); | |
| 534 if (candidate_device_id == device_id) { | |
| 535 DVLOG(1) << "Requested device " << device_name.unique_id << " - " | |
| 536 << device_name.device_name; | |
| 537 raw_device_id = device_name.unique_id; | |
| 538 } | |
| 539 } | |
| 540 | |
| 541 if (raw_device_id.empty()) { | |
| 542 DVLOG(1) << "Requested device " << device_id << " could not be found."; | |
| 543 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 544 stream_id, request_id, media::AudioOutputIPCDelegate::kNotFoundError)); | |
| 545 return; | |
| 546 } | |
| 547 | |
| 548 DoSwitchOutputDevice(stream_id, raw_device_id, request_id); | |
| 549 } | |
| 550 | |
| 551 void AudioRendererHost::DoSwitchOutputDevice(int stream_id, | |
| 552 const std::string& raw_device_id, | |
| 553 int request_id) { | |
| 554 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 555 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", " | |
| 556 << request_id << ")"; | |
| 557 AudioEntry* entry = LookupById(stream_id); | |
| 558 if (!entry) { | |
| 559 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 560 stream_id, request_id, media::AudioOutputIPCDelegate::kObsoleteError)); | |
| 561 return; | |
| 562 } | |
| 563 | |
| 564 entry->controller()->SwitchOutputDevice( | |
| 565 raw_device_id, base::Bind(&AudioRendererHost::DoOutputDeviceSwitched, | |
| 566 this, stream_id, request_id)); | |
| 567 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id); | |
| 568 } | |
| 569 | |
| 570 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) { | |
| 571 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 572 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")"; | |
| 573 Send(new AudioMsg_NotifyOutputDeviceSwitched( | |
| 574 stream_id, request_id, media::AudioOutputIPCDelegate::kSuccess)); | |
| 575 } | |
| 576 | |
| 425 void AudioRendererHost::SendErrorMessage(int stream_id) { | 577 void AudioRendererHost::SendErrorMessage(int stream_id) { |
| 426 Send(new AudioMsg_NotifyStreamStateChanged( | 578 Send(new AudioMsg_NotifyStreamStateChanged( |
| 427 stream_id, media::AudioOutputIPCDelegate::kError)); | 579 stream_id, media::AudioOutputIPCDelegate::kError)); |
| 428 } | 580 } |
| 429 | 581 |
| 430 void AudioRendererHost::OnCloseStream(int stream_id) { | 582 void AudioRendererHost::OnCloseStream(int stream_id) { |
| 431 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 583 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 432 | 584 |
| 433 // Prevent oustanding callbacks from attempting to close/delete the same | 585 // Prevent oustanding callbacks from attempting to close/delete the same |
| 434 // AudioEntry twice. | 586 // AudioEntry twice. |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 512 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); | 664 for (AudioEntryMap::const_iterator it = audio_entries_.begin(); |
| 513 it != audio_entries_.end(); | 665 it != audio_entries_.end(); |
| 514 ++it) { | 666 ++it) { |
| 515 AudioEntry* entry = it->second; | 667 AudioEntry* entry = it->second; |
| 516 if (entry->render_frame_id() == render_frame_id && entry->playing()) | 668 if (entry->render_frame_id() == render_frame_id && entry->playing()) |
| 517 return true; | 669 return true; |
| 518 } | 670 } |
| 519 return false; | 671 return false; |
| 520 } | 672 } |
| 521 | 673 |
| 674 bool AudioRendererHost::IsURLAllowed(const GURL& url) { | |
| 675 if (!ChildProcessSecurityPolicyImpl::GetInstance()->CanRequestURL( | |
| 676 render_process_id_, url)) { | |
| 677 LOG(ERROR) << "MSDH: Renderer requested a URL it's not allowed to use."; | |
|
ncarter (slow)
2015/06/10 18:10:48
You don't need this LOG if you switch to bad_messa
Guido Urdaneta
2015/06/11 00:51:57
Done.
| |
| 678 return false; | |
| 679 } | |
| 680 return true; | |
| 681 } | |
| 682 | |
| 522 } // namespace content | 683 } // namespace content |
| OLD | NEW |