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

Unified 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, 7 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/media/audio_renderer_host.cc
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc
index 5f140ac2b8ff7c4c301552632c5c0b8b9fc5c22a..a1fbad383be4c1a6642461affa409b8f8399b18d 100644
--- a/content/browser/renderer_host/media/audio_renderer_host.cc
+++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -18,13 +18,16 @@
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
#include "content/browser/renderer_host/media/audio_sync_reader.h"
#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/common/media/audio_messages.h"
#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/media_device_id.h"
#include "content/public/browser/media_observer.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/common/content_switches.h"
+#include "media/audio/audio_device_name.h"
#include "media/audio/audio_manager_base.h"
#include "media/base/audio_bus.h"
#include "media/base/limits.h"
@@ -146,7 +149,8 @@ AudioRendererHost::AudioRendererHost(
media::AudioManager* audio_manager,
AudioMirroringManager* mirroring_manager,
MediaInternals* media_internals,
- MediaStreamManager* media_stream_manager)
+ MediaStreamManager* media_stream_manager,
+ const ResourceContext::SaltCallback& salt_callback)
: BrowserMessageFilter(AudioMsgStart),
render_process_id_(render_process_id),
audio_manager_(audio_manager),
@@ -154,7 +158,8 @@ AudioRendererHost::AudioRendererHost(
audio_log_(media_internals->CreateAudioLog(
media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER)),
media_stream_manager_(media_stream_manager),
- num_playing_streams_(0) {
+ num_playing_streams_(0),
+ salt_callback_(salt_callback) {
DCHECK(audio_manager_);
DCHECK(media_stream_manager_);
}
@@ -310,6 +315,7 @@ bool AudioRendererHost::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER(AudioHostMsg_PauseStream, OnPauseStream)
IPC_MESSAGE_HANDLER(AudioHostMsg_CloseStream, OnCloseStream)
IPC_MESSAGE_HANDLER(AudioHostMsg_SetVolume, OnSetVolume)
+ IPC_MESSAGE_HANDLER(AudioHostMsg_SwitchOutputDevice, OnSwitchOutputDevice)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -422,6 +428,162 @@ void AudioRendererHost::OnSetVolume(int stream_id, double volume) {
audio_log_->OnSetVolume(stream_id, volume);
}
+void AudioRendererHost::OnSwitchOutputDevice(
+ int stream_id,
+ const std::string& device_id,
+ const GURL& security_origin,
+ int render_frame_id,
+ int request_id) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << "AudioRendererHost@" << this
+ << "::OnSwitchOutputDevice(stream_id=" << stream_id
+ << ", device_id=" << device_id
+ << ", security_origin=" << security_origin
+ << ", render_frame_id=" << render_frame_id
+ << ", request_id=" << request_id
+ << ")";
+
+ if (device_id.empty()) {
+ DVLOG(1) << __FUNCTION__ << ": default output device requested. "
+ <<"No permissions check or device translation/validation needed.";
+ DoSwitchOutputDevice(stream_id, device_id, request_id);
+ } else {
+ // 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
+ // hence the use of a MediaStreamUIProxy.
+ scoped_ptr<MediaStreamUIProxy> ui_proxy = MediaStreamUIProxy::Create();
+
+ // We use MEDIA_DEVICE_AUDIO_CAPTURE instead of MEDIA_DEVICE_AUDIO_OUTPUT
+ // because MediaStreamUIProxy::CheckAccess does not currently support
+ // MEDIA_DEVICE_AUDIO_OUTPUT.
+ ui_proxy->CheckAccess(security_origin,
+ MEDIA_DEVICE_AUDIO_CAPTURE,
+ render_process_id_,
+ render_frame_id,
+ base::Bind(
+ &AudioRendererHost::OutputDeviceAccessChecked,
+ this,
+ base::Passed(&ui_proxy),
+ stream_id,
+ device_id,
+ security_origin,
+ render_frame_id,
+ request_id));
+ }
+}
+
+void AudioRendererHost::OutputDeviceAccessChecked(
+ scoped_ptr<MediaStreamUIProxy> ui_proxy,
+ int stream_id,
+ const std::string& device_id,
+ const GURL& security_origin,
+ int render_frame_id,
+ int request_id,
+ bool have_access) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DVLOG(1) << __FUNCTION__;
+ if (!have_access) {
+ DVLOG(0) << __FUNCTION__
+ << ": Have no access to media devices. Not switching device.";
+ Send(new AudioMsg_NotifyOutputDeviceSwitched(
+ stream_id, request_id, media::AudioOutputIPCDelegate::kSecurityError));
+ return;
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> audio_worker_runner =
+ AudioManager::Get()->GetWorkerTaskRunner();
+ audio_worker_runner->PostTask(FROM_HERE, base::Bind(
+ &AudioRendererHost::StartTranslateOutputDeviceName,
+ this,
+ stream_id,
+ device_id,
+ security_origin,
+ request_id));
+}
+
+void AudioRendererHost::StartTranslateOutputDeviceName(
+ int stream_id,
+ const std::string& device_id,
+ const GURL& security_origin,
+ int request_id) {
+ DCHECK(AudioManager::Get()->GetWorkerTaskRunner()->BelongsToCurrentThread());
+ DCHECK(!device_id.empty());
+ DVLOG(1) << __FUNCTION__;
+
+ media::AudioDeviceNames* device_names = new media::AudioDeviceNames;
+ AudioManager::Get()->GetAudioOutputDeviceNames(device_names);
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&AudioRendererHost::FinishTranslateOutputDeviceName,
+ this,
+ stream_id,
+ device_id,
+ security_origin,
+ request_id,
+ base::Owned(device_names)));
+}
+
+void AudioRendererHost::FinishTranslateOutputDeviceName(
+ int stream_id,
+ const std::string& device_id,
+ const GURL& security_origin,
+ int request_id,
+ media::AudioDeviceNames* device_names) {
+ DCHECK_CURRENTLY_ON(BrowserThread::IO);
+ DCHECK(!device_id.empty());
+ DVLOG(1) << __FUNCTION__;
+
+ std::string raw_device_id = "";
+ // We process the enumeration here because |salt_callback_| can run
+ // only on the IO thread
+ for (const auto &device_name : *device_names) {
+ const std::string candidate_device_id =
+ content::GetHMACForMediaDeviceID(salt_callback_,
+ security_origin,
+ device_name.unique_id);
+ if (candidate_device_id == device_id) {
+ DVLOG(1) << "Requested device " << device_name.unique_id << " - "
+ << device_name.device_name;
+ raw_device_id = device_name.unique_id;
+ }
+ }
+
+ if (raw_device_id.empty()) {
+ DVLOG(1) << "Requested device " << device_id << " could not be found.";
+ Send(new AudioMsg_NotifyOutputDeviceSwitched(
+ stream_id, request_id, media::AudioOutputIPCDelegate::kNotFound));
+ return;
+ }
+
+ DoSwitchOutputDevice(stream_id, raw_device_id, request_id);
+}
+
+void AudioRendererHost::DoSwitchOutputDevice(
+ int stream_id, const std::string& raw_device_id, int request_id) {
+ DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << raw_device_id << ", "
miu 2015/06/03 21:01:01 nit: Add DCHECK_CURRENTLY_ON(...)
+ << request_id << ")";
+ AudioEntry* entry = LookupById(stream_id);
+ if (!entry) {
+ Send(new AudioMsg_NotifyOutputDeviceSwitched(
+ stream_id, request_id, media::AudioOutputIPCDelegate::kOtherError));
+ return;
+ }
+
+ entry->controller()->SwitchOutputDevice(
+ raw_device_id,
+ base::Bind(&AudioRendererHost::DoOutputDeviceSwitched,
+ this,
+ stream_id,
+ request_id));
+ audio_log_->OnSwitchOutputDevice(entry->stream_id(), raw_device_id);
+}
+
+void AudioRendererHost::DoOutputDeviceSwitched(int stream_id, int request_id) {
+ DVLOG(1) << __FUNCTION__ << "(" << stream_id << ", " << request_id << ")";
miu 2015/06/03 21:01:01 nit: Add DCHECK_CURRENTLY_ON(...)
+ Send(new AudioMsg_NotifyOutputDeviceSwitched(
+ stream_id, request_id, media::AudioOutputIPCDelegate::kSuccess));
+}
+
void AudioRendererHost::SendErrorMessage(int stream_id) {
Send(new AudioMsg_NotifyStreamStateChanged(
stream_id, media::AudioOutputIPCDelegate::kError));

Powered by Google App Engine
This is Rietveld 408576698