Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(583)

Side by Side Diff: content/browser/renderer_host/media/audio_renderer_host.cc

Issue 1122393004: Add support for switching the audio output device for HTMLMediaElements. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Changes to MediaPlayers so that they invoke callbacks in the correct threads. First complete implem… Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/loader/resource_dispatcher_host_impl.h" 14 #include "content/browser/loader/resource_dispatcher_host_impl.h"
15 #include "content/browser/media/audio_stream_monitor.h" 15 #include "content/browser/media/audio_stream_monitor.h"
16 #include "content/browser/media/capture/audio_mirroring_manager.h" 16 #include "content/browser/media/capture/audio_mirroring_manager.h"
17 #include "content/browser/media/media_internals.h" 17 #include "content/browser/media/media_internals.h"
18 #include "content/browser/renderer_host/media/audio_input_device_manager.h" 18 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
19 #include "content/browser/renderer_host/media/audio_sync_reader.h" 19 #include "content/browser/renderer_host/media/audio_sync_reader.h"
20 #include "content/browser/renderer_host/media/media_stream_manager.h" 20 #include "content/browser/renderer_host/media/media_stream_manager.h"
21 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
21 #include "content/browser/renderer_host/render_widget_host_impl.h" 22 #include "content/browser/renderer_host/render_widget_host_impl.h"
22 #include "content/common/media/audio_messages.h" 23 #include "content/common/media/audio_messages.h"
23 #include "content/public/browser/content_browser_client.h" 24 #include "content/public/browser/content_browser_client.h"
25 #include "content/public/browser/media_device_id.h"
24 #include "content/public/browser/media_observer.h" 26 #include "content/public/browser/media_observer.h"
25 #include "content/public/browser/render_frame_host.h" 27 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/render_view_host.h" 28 #include "content/public/browser/render_view_host.h"
27 #include "content/public/common/content_switches.h" 29 #include "content/public/common/content_switches.h"
30 #include "media/audio/audio_device_name.h"
28 #include "media/audio/audio_manager_base.h" 31 #include "media/audio/audio_manager_base.h"
29 #include "media/base/audio_bus.h" 32 #include "media/base/audio_bus.h"
30 #include "media/base/limits.h" 33 #include "media/base/limits.h"
31 34
32 using media::AudioBus; 35 using media::AudioBus;
33 using media::AudioManager; 36 using media::AudioManager;
34 37
35 namespace content { 38 namespace content {
36 39
37 namespace { 40 namespace {
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 AudioRendererHost::AudioEntry::~AudioEntry() {} 142 AudioRendererHost::AudioEntry::~AudioEntry() {}
140 143
141 /////////////////////////////////////////////////////////////////////////////// 144 ///////////////////////////////////////////////////////////////////////////////
142 // AudioRendererHost implementations. 145 // AudioRendererHost implementations.
143 146
144 AudioRendererHost::AudioRendererHost( 147 AudioRendererHost::AudioRendererHost(
145 int render_process_id, 148 int render_process_id,
146 media::AudioManager* audio_manager, 149 media::AudioManager* audio_manager,
147 AudioMirroringManager* mirroring_manager, 150 AudioMirroringManager* mirroring_manager,
148 MediaInternals* media_internals, 151 MediaInternals* media_internals,
149 MediaStreamManager* media_stream_manager) 152 MediaStreamManager* media_stream_manager,
153 const ResourceContext::SaltCallback& salt_callback)
150 : BrowserMessageFilter(AudioMsgStart), 154 : BrowserMessageFilter(AudioMsgStart),
151 render_process_id_(render_process_id), 155 render_process_id_(render_process_id),
152 audio_manager_(audio_manager), 156 audio_manager_(audio_manager),
153 mirroring_manager_(mirroring_manager), 157 mirroring_manager_(mirroring_manager),
154 audio_log_(media_internals->CreateAudioLog( 158 audio_log_(media_internals->CreateAudioLog(
155 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)), 159 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
156 media_stream_manager_(media_stream_manager), 160 media_stream_manager_(media_stream_manager),
157 num_playing_streams_(0) { 161 num_playing_streams_(0),
162 salt_callback_(salt_callback) {
158 DCHECK(audio_manager_); 163 DCHECK(audio_manager_);
159 DCHECK(media_stream_manager_); 164 DCHECK(media_stream_manager_);
160 } 165 }
161 166
162 AudioRendererHost::~AudioRendererHost() { 167 AudioRendererHost::~AudioRendererHost() {
163 DCHECK(audio_entries_.empty()); 168 DCHECK(audio_entries_.empty());
164 } 169 }
165 170
166 void AudioRendererHost::GetOutputControllers( 171 void AudioRendererHost::GetOutputControllers(
167 const RenderProcessHost::GetAudioOutputControllersCallback& 172 const RenderProcessHost::GetAudioOutputControllersCallback&
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 /////////////////////////////////////////////////////////////////////////////// 308 ///////////////////////////////////////////////////////////////////////////////
304 // IPC Messages handler 309 // IPC Messages handler
305 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) { 310 bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
306 bool handled = true; 311 bool handled = true;
307 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message) 312 IPC_BEGIN_MESSAGE_MAP(AudioRendererHost, message)
308 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream) 313 IPC_MESSAGE_HANDLER(AudioHostMsg_CreateStream, OnCreateStream)
309 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream) 314 IPC_MESSAGE_HANDLER(AudioHostMsg_PlayStream, OnPlayStream)
310 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream) 315 IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
311 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream) 316 IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
312 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume) 317 IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
318 IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
313 IPC_MESSAGE_UNHANDLED(handled = false) 319 IPC_MESSAGE_UNHANDLED(handled = false)
314 IPC_END_MESSAGE_MAP() 320 IPC_END_MESSAGE_MAP()
315 321
316 return handled; 322 return handled;
317 } 323 }
318 324
319 void AudioRendererHost::OnCreateStream(int stream_id, 325 void AudioRendererHost::OnCreateStream(int stream_id,
320 int render_frame_id, 326 int render_frame_id,
321 int session_id, 327 int session_id,
322 const media::AudioParameters& params) { 328 const media::AudioParameters& params) {
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
415 return; 421 return;
416 } 422 }
417 423
418 // Make sure the volume is valid. 424 // Make sure the volume is valid.
419 if (volume < 0 || volume > 1.0) 425 if (volume < 0 || volume > 1.0)
420 return; 426 return;
421 entry->controller()->SetVolume(volume); 427 entry->controller()->SetVolume(volume);
422 audio_log_->OnSetVolume(stream_id, volume); 428 audio_log_->OnSetVolume(stream_id, volume);
423 } 429 }
424 430
431 void AudioRendererHost::OnSwitchOutputDevice(
432 int stream_id,
433 const std::string& device_id,
434 const GURL& security_origin,
435 int render_frame_id,
436 int request_id) {
437 DCHECK_CURRENTLY_ON(BrowserThread::IO);
438 DVLOG(1) << "AudioRendererHost@" << this
439 << "::OnSwitchOutputDevice(stream_id=" << stream_id
440 << ", device_id=" << device_id
441 << ", security_origin=" << security_origin
442 << ", render_frame_id=" << render_frame_id
443 << ", request_id=" << request_id
444 << ")";
445
446 if (device_id.empty()) {
447 DVLOG(1) << __FUNCTION__ << ": default output device requested. "
448 <<"No permissions check or device translation/validation needed.";
449 DoSwitchOutputDevice(stream_id, device_id, request_id);
450 } else {
451 // We want to check that MediaStream device permissions have been granted,
miu 2015/06/03 21:01:01 nit: Please rewrite all code comments in this CL w
452 // hence the use of a MediaStreamUIProxy.
453 scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
454
455 // We use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
456 // because MediaStreamUIProxy::CheckAccess does not currently support
457 // MEDIA_DEVICE_AUDIO_OUTPUT.
458 ui_proxy->CheckAccess(security_origin,
459 MEDIA_DEVICE_AUDIO_CAPTURE,
460 render_process_id_,
461 render_frame_id,
462 base::Bind(
463 &AudioRendererHost::OutputDeviceAccessChecked,
464 this,
465 base::Passed(&ui_proxy),
466 stream_id,
467 device_id,
468 security_origin,
469 render_frame_id,
470 request_id));
471 }
472 }
473
474 void AudioRendererHost::OutputDeviceAccessChecked(
475 scoped_ptr<MediaStreamUIProxy> ui_proxy,
476 int stream_id,
477 const std::string& device_id,
478 const GURL& security_origin,
479 int render_frame_id,
480 int request_id,
481 bool have_access) {
482 DCHECK_CURRENTLY_ON(BrowserThread::IO);
483 DVLOG(1) << __FUNCTION__;
484 if (!have_access) {
485 DVLOG(0) << __FUNCTION__
486 << ": Have no access to media devices. Not switching device.";
487 Send(new AudioMsg_NotifyOutputDeviceSwitched(
488 stream_id, request_id, media::AudioOutputIPCDelegate::kSecurityError));
489 return;
490 }
491
492 scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
493 AudioManager::Get()->GetWorkerTaskRunner();
494 audio_worker_runner->PostTask(FROM_HERE, base::Bind(
495 &AudioRendererHost::StartTranslateOutputDeviceName,
496 this,
497 stream_id,
498 device_id,
499 security_origin,
500 request_id));
501 }
502
503 void AudioRendererHost::StartTranslateOutputDeviceName(
504 int stream_id,
505 const std::string& device_id,
506 const GURL& security_origin,
507 int request_id) {
508 DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
509 DCHECK(!device_id.empty());
510 DVLOG(1) << __FUNCTION__;
511
512 media::AudioDeviceNames* device_names = new media::AudioDeviceNames;
513 AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
514
515 BrowserThread::PostTask(
516 BrowserThread::IO, FROM_HERE,
517 base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName,
518 this,
519 stream_id,
520 device_id,
521 security_origin,
522 request_id,
523 base::Owned(device_names)));
524 }
525
526 void AudioRendererHost::FinishTranslateOutputDeviceName(
527 int stream_id,
528 const std::string& device_id,
529 const GURL& security_origin,
530 int request_id,
531 media::AudioDeviceNames* device_names) {
532 DCHECK_CURRENTLY_ON(BrowserThread::IO);
533 DCHECK(!device_id.empty());
534 DVLOG(1) << __FUNCTION__;
535
536 std::string raw_device_id = "";
537 // We process the enumeration here because |salt_callback_| can run
538 // only on the IO thread
539 for (const auto &device_name : *device_names) {
540 const std::string candidate_device_id =
541 content::GetHMACForMediaDeviceID(salt_callback_,
542 security_origin,
543 device_name.unique_id);
544 if (candidate_device_id == device_id) {
545 DVLOG(1) << "Requested device " << device_name.unique_id << " - "
546 << device_name.device_name;
547 raw_device_id = device_name.unique_id;
548 }
549 }
550
551 if (raw_device_id.empty()) {
552 DVLOG(1) << "Requested device " << device_id << " could not be found.";
553 Send(new AudioMsg_NotifyOutputDeviceSwitched(
554 stream_id, request_id, media::AudioOutputIPCDelegate::kNotFound));
555 return;
556 }
557
558 DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
559 }
560
561 void AudioRendererHost::DoSwitchOutputDevice(
562 int stream_id, const std::string& raw_device_id, int request_id) {
563 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
miu 2015/06/03 21:01:01 nit: Add DCHECK_CURRENTLY_ON(...)
564 << request_id << ")";
565 AudioEntry* entry = LookupById(stream_id);
566 if (!entry) {
567 Send(new AudioMsg_NotifyOutputDeviceSwitched(
568 stream_id, request_id, media::AudioOutputIPCDelegate::kOtherError));
569 return;
570 }
571
572 entry->controller()->SwitchOutputDevice(
573 raw_device_id,
574 base::Bind(&AudioRendererHost::DoOutputDeviceSwitched,
575 this,
576 stream_id,
577 request_id));
578 audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id);
579 }
580
581 void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) {
582 DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
miu 2015/06/03 21:01:01 nit: Add DCHECK_CURRENTLY_ON(...)
583 Send(new AudioMsg_NotifyOutputDeviceSwitched(
584 stream_id, request_id, media::AudioOutputIPCDelegate::kSuccess));
585 }
586
425 void AudioRendererHost::SendErrorMessage(int stream_id) { 587 void AudioRendererHost::SendErrorMessage(int stream_id) {
426 Send(new AudioMsg_NotifyStreamStateChanged( 588 Send(new AudioMsg_NotifyStreamStateChanged(
427 stream_id, media::AudioOutputIPCDelegate::kError)); 589 stream_id, media::AudioOutputIPCDelegate::kError));
428 } 590 }
429 591
430 void AudioRendererHost::OnCloseStream(int stream_id) { 592 void AudioRendererHost::OnCloseStream(int stream_id) {
431 DCHECK_CURRENTLY_ON(BrowserThread::IO); 593 DCHECK_CURRENTLY_ON(BrowserThread::IO);
432 594
433 // Prevent oustanding callbacks from attempting to close/delete the same 595 // Prevent oustanding callbacks from attempting to close/delete the same
434 // AudioEntry twice. 596 // AudioEntry twice.
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
513 it != audio_entries_.end(); 675 it != audio_entries_.end();
514 ++it) { 676 ++it) {
515 AudioEntry* entry = it->second; 677 AudioEntry* entry = it->second;
516 if (entry->render_frame_id() == render_frame_id && entry->playing()) 678 if (entry->render_frame_id() == render_frame_id && entry->playing())
517 return true; 679 return true;
518 } 680 }
519 return false; 681 return false;
520 } 682 }
521 683
522 } // namespace content 684 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698