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

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

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

Powered by Google App Engine
This is Rietveld 408576698