summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvrk@chromium.org <vrk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-17 04:06:32 +0000
committervrk@chromium.org <vrk@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-17 04:06:32 +0000
commitc129874dc579801d403c521fe0ebe38fbc1cf2f2 (patch)
tree13000674cd15260abb8f2a9f5310c91fcaa91a85
parent9898e98903866d064ff4a30d72baa0222f6556e2 (diff)
downloadchromium_src-c129874dc579801d403c521fe0ebe38fbc1cf2f2.zip
chromium_src-c129874dc579801d403c521fe0ebe38fbc1cf2f2.tar.gz
chromium_src-c129874dc579801d403c521fe0ebe38fbc1cf2f2.tar.bz2
Implement Chromium backend for getSourceInfos()
BUG=240710,https://code.google.com/p/webrtc/issues/detail?id=1571 Review URL: https://chromiumcodereview.appspot.com/16806002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211922 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd6
-rw-r--r--chrome/browser/about_flags.cc7
-rw-r--r--chrome/browser/media/media_capture_devices_dispatcher.cc86
-rw-r--r--chrome/browser/media/media_capture_devices_dispatcher.h24
-rw-r--r--chrome/browser/media/media_stream_devices_controller.cc70
-rw-r--r--chrome/browser/policy/policy_browsertest.cc11
-rw-r--r--content/browser/renderer_host/media/device_request_message_filter.cc195
-rw-r--r--content/browser/renderer_host/media/device_request_message_filter.h73
-rw-r--r--content/browser/renderer_host/media/device_request_message_filter_unittest.cc258
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc83
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h27
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc16
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc3
-rw-r--r--content/common/media/media_stream_messages.h14
-rw-r--r--content/common/media/media_stream_options.cc1
-rw-r--r--content/common/media/media_stream_options.h1
-rw-r--r--content/content_browser.gypi2
-rw-r--r--content/content_tests.gypi1
-rw-r--r--content/public/common/content_switches.cc4
-rw-r--r--content/public/common/content_switches.h3
-rw-r--r--content/public/common/media_stream_request.cc8
-rw-r--r--content/public/common/media_stream_request.h23
-rw-r--r--content/renderer/media/media_stream_center.cc58
-rw-r--r--content/renderer/media/media_stream_center.h37
-rw-r--r--content/renderer/media/media_stream_impl.cc39
-rw-r--r--content/renderer/render_thread_impl.cc6
26 files changed, 942 insertions, 114 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 16d2d0d..87e5814 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6780,6 +6780,12 @@ Keep your key file in a safe place. You will need it to create new versions of y
<message name="IDS_FLAGS_ENABLE_SCTP_DATA_CHANNELS_DESCRIPTION" desc="Description of about:flags option to turn on SCTP data channels support">
When enabled, DataChannels created by WebRTC will use the SCTP wire protocol.
</message>
+ <message name="IDS_FLAGS_ENABLE_DEVICE_ENUMERATION_NAME" desc="Name of about:flags option to turn on WebRTC device enumeration support.">
+ Enable WebRTC device enumeration.
+ </message>
+ <message name="IDS_FLAGS_ENABLE_DEVICE_ENUMERATION_DESCRIPTION" desc="Description of chrome:flags option to turn on WebRTC device enumeration support">
+ When enabled, MediaStreamTrack can list the available video and audio input devices, and getUserMedia can open these input devices by referencing an opaque id.
+ </message>
<message name="IDS_FLAGS_DISABLE_WEBAUDIO_NAME" desc="Name of the 'Disable WebAudio' lab.">
Disable WebAudio
</message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 63db52c..fd0c851 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -464,6 +464,13 @@ const Experiment kExperiments[] = {
kOsAll,
SINGLE_VALUE_TYPE(switches::kEnableSCTPDataChannels)
},
+ {
+ "enable-device-enumeration",
+ IDS_FLAGS_ENABLE_DEVICE_ENUMERATION_NAME,
+ IDS_FLAGS_ENABLE_DEVICE_ENUMERATION_DESCRIPTION,
+ kOsAll,
+ SINGLE_VALUE_TYPE(switches::kEnableDeviceEnumeration)
+ },
#endif
#if defined(OS_ANDROID)
{
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index 340ef6b..6d49f98 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -40,20 +40,17 @@ using content::MediaStreamDevices;
namespace {
-const content::MediaStreamDevice* FindDefaultDeviceWithId(
+// Finds a device in |devices| that has |device_id|, or NULL if not found.
+const content::MediaStreamDevice* FindDeviceWithId(
const content::MediaStreamDevices& devices,
const std::string& device_id) {
- if (devices.empty())
- return NULL;
-
content::MediaStreamDevices::const_iterator iter = devices.begin();
for (; iter != devices.end(); ++iter) {
if (iter->id == device_id) {
return &(*iter);
}
}
-
- return &(*devices.begin());
+ return NULL;
};
// This is a short-term solution to allow testing of the the Screen Capture API
@@ -242,7 +239,6 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequestFromExtension(
content::MediaStreamDevices devices;
Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext());
- PrefService* prefs = profile->GetPrefs();
#if defined(OS_ANDROID)
// Tab capture is not supported on Android.
@@ -264,9 +260,7 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequestFromExtension(
} else if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE &&
extension->HasAPIPermission(
extensions::APIPermission::kAudioCapture)) {
- std::string default_device =
- prefs->GetString(prefs::kDefaultAudioCaptureDevice);
- GetRequestedDevice(default_device, true, false, &devices);
+ GetDefaultDevicesForProfile(profile, true, false, &devices);
}
if (request.video_type == content::MEDIA_TAB_VIDEO_CAPTURE &&
@@ -277,9 +271,7 @@ void MediaCaptureDevicesDispatcher::ProcessMediaAccessRequestFromExtension(
content::MEDIA_TAB_VIDEO_CAPTURE, std::string(), std::string()));
} else if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE &&
extension->HasAPIPermission(extensions::APIPermission::kVideoCapture)) {
- std::string default_device = prefs->GetString(
- prefs::kDefaultVideoCaptureDevice);
- GetRequestedDevice(default_device, false, true, &devices);
+ GetDefaultDevicesForProfile(profile, false, true, &devices);
}
scoped_ptr<content::MediaStreamUI> ui;
@@ -369,37 +361,61 @@ void MediaCaptureDevicesDispatcher::GetDefaultDevicesForProfile(
std::string default_device;
if (audio) {
default_device = prefs->GetString(prefs::kDefaultAudioCaptureDevice);
- GetRequestedDevice(default_device, true, false, devices);
+ const content::MediaStreamDevice* device =
+ GetRequestedAudioDevice(default_device);
+ if (!device)
+ device = GetFirstAvailableAudioDevice();
+ if (device)
+ devices->push_back(*device);
}
if (video) {
default_device = prefs->GetString(prefs::kDefaultVideoCaptureDevice);
- GetRequestedDevice(default_device, false, true, devices);
+ const content::MediaStreamDevice* device =
+ GetRequestedVideoDevice(default_device);
+ if (!device)
+ device = GetFirstAvailableVideoDevice();
+ if (device)
+ devices->push_back(*device);
}
}
-void MediaCaptureDevicesDispatcher::GetRequestedDevice(
- const std::string& requested_device_id,
- bool audio,
- bool video,
- content::MediaStreamDevices* devices) {
+const content::MediaStreamDevice*
+MediaCaptureDevicesDispatcher::GetRequestedAudioDevice(
+ const std::string& requested_audio_device_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- DCHECK(audio || video);
+ const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
+ const content::MediaStreamDevice* const device =
+ FindDeviceWithId(audio_devices, requested_audio_device_id);
+ return device;
+}
- if (audio) {
- const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
- const content::MediaStreamDevice* const device =
- FindDefaultDeviceWithId(audio_devices, requested_device_id);
- if (device)
- devices->push_back(*device);
- }
- if (video) {
- const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
- const content::MediaStreamDevice* const device =
- FindDefaultDeviceWithId(video_devices, requested_device_id);
- if (device)
- devices->push_back(*device);
- }
+const content::MediaStreamDevice*
+MediaCaptureDevicesDispatcher::GetFirstAvailableAudioDevice() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const content::MediaStreamDevices& audio_devices = GetAudioCaptureDevices();
+ if (audio_devices.empty())
+ return NULL;
+ return &(*audio_devices.begin());
+}
+
+const content::MediaStreamDevice*
+MediaCaptureDevicesDispatcher::GetRequestedVideoDevice(
+ const std::string& requested_video_device_id) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
+ const content::MediaStreamDevice* const device =
+ FindDeviceWithId(video_devices, requested_video_device_id);
+ return device;
+}
+
+const content::MediaStreamDevice*
+MediaCaptureDevicesDispatcher::GetFirstAvailableVideoDevice() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ const content::MediaStreamDevices& video_devices = GetVideoCaptureDevices();
+ if (video_devices.empty())
+ return NULL;
+ return &(*video_devices.begin());
}
void MediaCaptureDevicesDispatcher::DisableDeviceEnumerationForTesting() {
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.h b/chrome/browser/media/media_capture_devices_dispatcher.h
index 801ab72..6054a30f 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.h
+++ b/chrome/browser/media/media_capture_devices_dispatcher.h
@@ -79,8 +79,9 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver,
const content::MediaResponseCallback& callback,
const extensions::Extension* extension);
- // Helper to get the default devices which can be used by the media request,
- // if the return list is empty, it means there is no available device on the
+ // Helper to get the default devices which can be used by the media request.
+ // Uses the first available devices if the default devices are not available.
+ // If the return list is empty, it means there is no available device on the
// OS.
// Called on the UI thread.
void GetDefaultDevicesForProfile(Profile* profile,
@@ -88,14 +89,17 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver,
bool video,
content::MediaStreamDevices* devices);
- // Helper for picking the device that was requested for an OpenDevice request.
- // If the device requested is not available it will revert to using the first
- // available one instead or will return an empty list if no devices of the
- // requested kind are present.
- void GetRequestedDevice(const std::string& requested_device_id,
- bool audio,
- bool video,
- content::MediaStreamDevices* devices);
+ // Helpers for picking particular requested devices, identified by raw id.
+ // If the device requested is not available it will return NULL.
+ const content::MediaStreamDevice*
+ GetRequestedAudioDevice(const std::string& requested_audio_device_id);
+ const content::MediaStreamDevice*
+ GetRequestedVideoDevice(const std::string& requested_video_device_id);
+
+ // Returns the first available audio or video device, or NULL if no devices
+ // are available.
+ const content::MediaStreamDevice* GetFirstAvailableAudioDevice();
+ const content::MediaStreamDevice* GetFirstAvailableVideoDevice();
// Unittests that do not require actual device enumeration should call this
// API on the singleton. It is safe to call this multiple times on the
diff --git a/chrome/browser/media/media_stream_devices_controller.cc b/chrome/browser/media/media_stream_devices_controller.cc
index e7f932a..04c5cf6 100644
--- a/chrome/browser/media/media_stream_devices_controller.cc
+++ b/chrome/browser/media/media_stream_devices_controller.cc
@@ -166,18 +166,66 @@ void MediaStreamDevicesController::Accept(bool update_content_setting) {
content::MediaStreamDevices devices;
if (microphone_requested_ || webcam_requested_) {
switch (request_.request_type) {
- case content::MEDIA_OPEN_DEVICE:
+ case content::MEDIA_OPEN_DEVICE: {
+ const content::MediaStreamDevice* device = NULL;
// For open device request pick the desired device or fall back to the
// first available of the given type.
- MediaCaptureDevicesDispatcher::GetInstance()->GetRequestedDevice(
- request_.requested_device_id,
- request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE,
- request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE,
- &devices);
+ if (request_.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) {
+ device = MediaCaptureDevicesDispatcher::GetInstance()->
+ GetRequestedAudioDevice(request_.requested_audio_device_id);
+ // TODO(wjia): Confirm this is the intended behavior.
+ if (!device) {
+ device = MediaCaptureDevicesDispatcher::GetInstance()->
+ GetFirstAvailableAudioDevice();
+ }
+ } else if (request_.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) {
+ // Pepper API opens only one device at a time.
+ device = MediaCaptureDevicesDispatcher::GetInstance()->
+ GetRequestedVideoDevice(request_.requested_video_device_id);
+ // TODO(wjia): Confirm this is the intended behavior.
+ if (!device) {
+ device = MediaCaptureDevicesDispatcher::GetInstance()->
+ GetFirstAvailableVideoDevice();
+ }
+ }
+ if (device)
+ devices.push_back(*device);
break;
- case content::MEDIA_DEVICE_ACCESS:
- case content::MEDIA_GENERATE_STREAM:
- case content::MEDIA_ENUMERATE_DEVICES:
+ } case content::MEDIA_GENERATE_STREAM: {
+ bool needs_audio_device = microphone_requested_;
+ bool needs_video_device = webcam_requested_;
+
+ // Get the exact audio or video device if an id is specified.
+ if (!request_.requested_audio_device_id.empty()) {
+ const content::MediaStreamDevice* audio_device =
+ MediaCaptureDevicesDispatcher::GetInstance()->
+ GetRequestedAudioDevice(request_.requested_audio_device_id);
+ if (audio_device) {
+ devices.push_back(*audio_device);
+ needs_audio_device = false;
+ }
+ }
+ if (!request_.requested_video_device_id.empty()) {
+ const content::MediaStreamDevice* video_device =
+ MediaCaptureDevicesDispatcher::GetInstance()->
+ GetRequestedVideoDevice(request_.requested_video_device_id);
+ if (video_device) {
+ devices.push_back(*video_device);
+ needs_video_device = false;
+ }
+ }
+
+ // If either or both audio and video devices were requested but not
+ // specified by id, get the default devices.
+ if (needs_audio_device || needs_video_device) {
+ MediaCaptureDevicesDispatcher::GetInstance()->
+ GetDefaultDevicesForProfile(profile_,
+ needs_audio_device,
+ needs_video_device,
+ &devices);
+ }
+ break;
+ } case content::MEDIA_DEVICE_ACCESS:
// Get the default devices for the request.
MediaCaptureDevicesDispatcher::GetInstance()->
GetDefaultDevicesForProfile(profile_,
@@ -185,6 +233,10 @@ void MediaStreamDevicesController::Accept(bool update_content_setting) {
webcam_requested_,
&devices);
break;
+ case content::MEDIA_ENUMERATE_DEVICES:
+ // Do nothing.
+ NOTREACHED();
+ break;
}
// TODO(raymes): We currently set the content permission for non-https
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index 2530479..87f9f7e 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -2296,9 +2296,10 @@ class MediaStreamDevicesControllerBrowserTest
}
void FinishAudioTest() {
- content::MediaStreamRequest request(0, 0, 0, request_url_.GetOrigin(),
+ content::MediaStreamRequest request(0, 0, 0, std::string(),
+ request_url_.GetOrigin(),
content::MEDIA_DEVICE_ACCESS,
- "fake_dev",
+ std::string(), std::string(),
content::MEDIA_DEVICE_AUDIO_CAPTURE,
content::MEDIA_NO_SERVICE);
// TODO(raymes): Test MEDIA_DEVICE_OPEN (Pepper) which grants both webcam
@@ -2314,9 +2315,11 @@ class MediaStreamDevicesControllerBrowserTest
void FinishVideoTest() {
// TODO(raymes): Test MEDIA_DEVICE_OPEN (Pepper) which grants both webcam
// and microphone permissions at the same time.
- content::MediaStreamRequest request(0, 0, 0, request_url_.GetOrigin(),
+ content::MediaStreamRequest request(0, 0, 0, std::string(),
+ request_url_.GetOrigin(),
content::MEDIA_DEVICE_ACCESS,
- "fake_dev",
+ std::string(),
+ std::string(),
content::MEDIA_NO_SERVICE,
content::MEDIA_DEVICE_VIDEO_CAPTURE);
MediaStreamDevicesController controller(
diff --git a/content/browser/renderer_host/media/device_request_message_filter.cc b/content/browser/renderer_host/media/device_request_message_filter.cc
new file mode 100644
index 0000000..bcd9dcf
--- /dev/null
+++ b/content/browser/renderer_host/media/device_request_message_filter.cc
@@ -0,0 +1,195 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include "content/browser/renderer_host/media/device_request_message_filter.h"
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "content/browser/browser_main_loop.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/common/media/media_stream_messages.h"
+#include "crypto/hmac.h"
+
+namespace content {
+
+DeviceRequestMessageFilter::DeviceRequestMessageFilter(
+ MediaStreamManager* media_stream_manager)
+ : media_stream_manager_(media_stream_manager) {
+ DCHECK(media_stream_manager);
+}
+
+DeviceRequestMessageFilter::~DeviceRequestMessageFilter() {
+ DCHECK(requests_.empty());
+}
+
+struct DeviceRequestMessageFilter::DeviceRequest {
+ DeviceRequest(int request_id,
+ const GURL& origin,
+ const std::string& audio_devices_label,
+ const std::string& video_devices_label)
+ : request_id(request_id),
+ origin(origin),
+ has_audio_returned(false),
+ has_video_returned(false),
+ audio_devices_label(audio_devices_label),
+ video_devices_label(video_devices_label) {}
+
+ int request_id;
+ GURL origin;
+ bool has_audio_returned;
+ bool has_video_returned;
+ std::string audio_devices_label;
+ std::string video_devices_label;
+ StreamDeviceInfoArray audio_devices;
+ StreamDeviceInfoArray video_devices;
+};
+
+void DeviceRequestMessageFilter::StreamGenerated(
+ const std::string& label,
+ const StreamDeviceInfoArray& audio_devices,
+ const StreamDeviceInfoArray& video_devices) {
+ NOTIMPLEMENTED();
+}
+
+void DeviceRequestMessageFilter::StreamGenerationFailed(
+ const std::string& label) {
+ NOTIMPLEMENTED();
+}
+
+void DeviceRequestMessageFilter::DevicesEnumerated(
+ const std::string& label,
+ const StreamDeviceInfoArray& new_devices) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ // Look up the DeviceRequest by id.
+ DeviceRequestList::iterator request_it = requests_.begin();
+ for (; request_it != requests_.end(); ++request_it) {
+ if (label == request_it->audio_devices_label ||
+ label == request_it->video_devices_label) {
+ break;
+ }
+ }
+ DCHECK(request_it != requests_.end());
+
+ StreamDeviceInfoArray* audio_devices = &request_it->audio_devices;
+ StreamDeviceInfoArray* video_devices = &request_it->video_devices;
+
+ // Store hmac'd device ids instead of raw device ids.
+ if (label == request_it->audio_devices_label) {
+ request_it->has_audio_returned = true;
+ DCHECK(audio_devices->empty());
+ HmacDeviceIds(request_it->origin, new_devices, audio_devices);
+ } else {
+ DCHECK(label == request_it->video_devices_label);
+ request_it->has_video_returned = true;
+ DCHECK(video_devices->empty());
+ HmacDeviceIds(request_it->origin, new_devices, video_devices);
+ }
+
+ if (!request_it->has_audio_returned || !request_it->has_video_returned) {
+ // Wait for the rest of the devices to complete.
+ return;
+ }
+
+ // Both audio and video devices are ready.
+ StreamDeviceInfoArray all_devices = *audio_devices;
+ all_devices.insert(
+ all_devices.end(), video_devices->begin(), video_devices->end());
+
+ Send(new MediaStreamMsg_GetSourcesACK(request_it->request_id, all_devices));
+
+ // TODO(vrk): Rename StopGeneratedStream() to CancelDeviceRequest().
+ media_stream_manager_->StopGeneratedStream(request_it->audio_devices_label);
+ media_stream_manager_->StopGeneratedStream(request_it->video_devices_label);
+ requests_.erase(request_it);
+}
+
+void DeviceRequestMessageFilter::DeviceOpened(
+ const std::string& label,
+ const StreamDeviceInfo& video_device) {
+ NOTIMPLEMENTED();
+}
+
+bool DeviceRequestMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(DeviceRequestMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(MediaStreamHostMsg_GetSources, OnGetSources)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP_EX()
+ return handled;
+}
+
+void DeviceRequestMessageFilter::OnChannelClosing() {
+ BrowserMessageFilter::OnChannelClosing();
+
+ // Since the IPC channel is gone, cancel outstanding device requests.
+ for (DeviceRequestList::iterator it = requests_.begin();
+ it != requests_.end();
+ ++it) {
+ // TODO(vrk): Rename StopGeneratedStream() to CancelDeviceRequest().
+ media_stream_manager_->StopGeneratedStream(it->audio_devices_label);
+ media_stream_manager_->StopGeneratedStream(it->video_devices_label);
+ }
+ requests_.clear();
+}
+
+void DeviceRequestMessageFilter::HmacDeviceIds(
+ const GURL& origin,
+ const StreamDeviceInfoArray& raw_devices,
+ StreamDeviceInfoArray* devices_with_guids) {
+ DCHECK(devices_with_guids);
+
+ // Replace raw ids with hmac'd ids before returning to renderer process.
+ for (StreamDeviceInfoArray::const_iterator device_itr = raw_devices.begin();
+ device_itr != raw_devices.end();
+ ++device_itr) {
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ const size_t digest_length = hmac.DigestLength();
+ std::vector<uint8> digest(digest_length);
+ bool result = hmac.Init(origin.spec()) &&
+ hmac.Sign(device_itr->device.id, &digest[0], digest.size());
+ DCHECK(result);
+ if (result) {
+ StreamDeviceInfo current_device_info = *device_itr;
+ current_device_info.device.id =
+ StringToLowerASCII(base::HexEncode(&digest[0], digest.size()));
+ devices_with_guids->push_back(current_device_info);
+ }
+ }
+}
+
+bool DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+ const GURL& security_origin,
+ const std::string& device_guid,
+ const std::string& raw_device_id) {
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ bool result = hmac.Init(security_origin.spec());
+ DCHECK(result);
+ std::vector<uint8> converted_guid;
+ base::HexStringToBytes(device_guid, &converted_guid);
+ return hmac.Verify(
+ raw_device_id,
+ base::StringPiece(reinterpret_cast<const char*>(&converted_guid[0]),
+ converted_guid.size()));
+}
+
+void DeviceRequestMessageFilter::OnGetSources(int request_id,
+ const GURL& security_origin) {
+ // Make request to get audio devices.
+ const std::string& audio_label = media_stream_manager_->EnumerateDevices(
+ this, -1, -1, -1, MEDIA_DEVICE_AUDIO_CAPTURE, security_origin);
+ DCHECK(!audio_label.empty());
+
+ // Make request for video devices.
+ const std::string& video_label = media_stream_manager_->EnumerateDevices(
+ this, -1, -1, -1, MEDIA_DEVICE_VIDEO_CAPTURE, security_origin);
+ DCHECK(!video_label.empty());
+
+ requests_.push_back(DeviceRequest(
+ request_id, security_origin, audio_label, video_label));
+}
+
+} // namespace content
diff --git a/content/browser/renderer_host/media/device_request_message_filter.h b/content/browser/renderer_host/media/device_request_message_filter.h
new file mode 100644
index 0000000..4e42186
--- /dev/null
+++ b/content/browser/renderer_host/media/device_request_message_filter.h
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_CENTER_HOST_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_CENTER_HOST_H_
+
+#include <map>
+#include <string>
+
+#include "base/synchronization/lock.h"
+#include "content/browser/renderer_host/media/media_stream_requester.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace content {
+
+class MediaStreamManager;
+
+// DeviceRequestMessageFilter used to delegate requests from the
+// MediaStreamCenter.
+class CONTENT_EXPORT DeviceRequestMessageFilter : public BrowserMessageFilter,
+ public MediaStreamRequester {
+ public:
+ explicit DeviceRequestMessageFilter(MediaStreamManager* media_stream_manager);
+
+ // MediaStreamRequester implementation.
+ // TODO(vrk): Replace MediaStreamRequester interface with a single callback so
+ // we don't have to override all these callbacks we don't care about.
+ // (crbug.com/249476)
+ virtual void StreamGenerated(
+ const std::string& label, const StreamDeviceInfoArray& audio_devices,
+ const StreamDeviceInfoArray& video_devices) OVERRIDE;
+ virtual void StreamGenerationFailed(const std::string& label) OVERRIDE;
+ virtual void DeviceOpened(const std::string& label,
+ const StreamDeviceInfo& video_device) OVERRIDE;
+ // DevicesEnumerated() is the only callback we're interested in.
+ virtual void DevicesEnumerated(const std::string& label,
+ const StreamDeviceInfoArray& devices) OVERRIDE;
+
+ // BrowserMessageFilter implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) OVERRIDE;
+ virtual void OnChannelClosing() OVERRIDE;
+
+ // Helper method that checks whether the GUID generated by
+ // DeviceRequestMessageFilter matches the given |raw_device_id|.
+ static bool DoesRawIdMatchGuid(const GURL& security_origin,
+ const std::string& device_guid,
+ const std::string& raw_device_id);
+
+ protected:
+ virtual ~DeviceRequestMessageFilter();
+
+ private:
+ void OnGetSources(int request_id, const GURL& security_origin);
+ void HmacDeviceIds(const GURL& origin,
+ const StreamDeviceInfoArray& raw_devices,
+ StreamDeviceInfoArray* devices_with_guids);
+
+ MediaStreamManager* media_stream_manager_;
+
+ struct DeviceRequest;
+ typedef std::vector<DeviceRequest> DeviceRequestList;
+ // List of all requests.
+ DeviceRequestList requests_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceRequestMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_RENDERER_HOST_MEDIA_MEDIA_STREAM_CENTER_HOST_H_
diff --git a/content/browser/renderer_host/media/device_request_message_filter_unittest.cc b/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
new file mode 100644
index 0000000..9043027
--- /dev/null
+++ b/content/browser/renderer_host/media/device_request_message_filter_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_number_conversions.h"
+#include "content/browser/renderer_host/media/device_request_message_filter.h"
+#include "content/browser/renderer_host/media/media_stream_manager.h"
+#include "content/common/media/media_stream_messages.h"
+#include "content/public/test/test_browser_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+
+namespace content {
+
+static const std::string kAudioLabel = "audio_label";
+static const std::string kVideoLabel = "video_label";
+
+class MockMediaStreamManager : public MediaStreamManager {
+ public:
+ MockMediaStreamManager() {}
+
+ virtual ~MockMediaStreamManager() {}
+
+ MOCK_METHOD6(EnumerateDevices,
+ std::string(MediaStreamRequester* requester,
+ int render_process_id,
+ int render_view_id,
+ int page_request_id,
+ MediaStreamType type,
+ const GURL& security_origin));
+ MOCK_METHOD1(StopGeneratedStream, void(const std::string& label));
+
+ std::string DoEnumerateDevices(MediaStreamRequester* requester,
+ int render_process_id,
+ int render_view_id,
+ int page_request_id,
+ MediaStreamType type,
+ const GURL& security_origin) {
+ if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
+ return kAudioLabel;
+ } else {
+ return kVideoLabel;
+ }
+ }
+};
+
+class MockDeviceRequestMessageFilter : public DeviceRequestMessageFilter {
+ public:
+ MockDeviceRequestMessageFilter(MockMediaStreamManager* manager)
+ : DeviceRequestMessageFilter(manager), received_id_(-1) {}
+ StreamDeviceInfoArray requested_devices() { return requested_devices_; }
+ int received_id() { return received_id_; }
+
+ private:
+ virtual ~MockDeviceRequestMessageFilter() {}
+
+ // Override the Send() method to intercept the message that we're sending to
+ // the renderer.
+ virtual bool Send(IPC::Message* reply_msg) OVERRIDE {
+ CHECK(reply_msg);
+
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(MockDeviceRequestMessageFilter, *reply_msg)
+ IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK, SaveDevices)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ EXPECT_TRUE(handled);
+
+ delete reply_msg;
+ return true;
+ }
+
+ void SaveDevices(int request_id, const StreamDeviceInfoArray& devices) {
+ received_id_ = request_id;
+ requested_devices_ = devices;
+ }
+
+ int received_id_;
+ StreamDeviceInfoArray requested_devices_;
+};
+
+class DeviceRequestMessageFilterTest : public testing::Test {
+ public:
+ DeviceRequestMessageFilterTest() : next_device_id_(0) {}
+
+ void RunTest(int number_audio_devices, int number_video_devices) {
+ AddAudioDevices(number_audio_devices);
+ AddVideoDevices(number_video_devices);
+ GURL origin("https://test.com");
+ EXPECT_CALL(*media_stream_manager_,
+ EnumerateDevices(_, _, _, _, MEDIA_DEVICE_AUDIO_CAPTURE, _))
+ .Times(1);
+ EXPECT_CALL(*media_stream_manager_,
+ EnumerateDevices(_, _, _, _, MEDIA_DEVICE_VIDEO_CAPTURE, _))
+ .Times(1);
+ // Send message to get devices. Should trigger 2 EnumerateDevice() requests.
+ const int kRequestId = 123;
+ SendGetSourcesMessage(kRequestId, origin);
+
+ // Run audio callback. Because there's still an outstanding video request,
+ // this should not populate |message|.
+ FireAudioDeviceCallback();
+ EXPECT_EQ(0u, host_->requested_devices().size());
+
+ // After the video device callback is fired, |message| should be populated.
+ EXPECT_CALL(*media_stream_manager_, StopGeneratedStream(kAudioLabel))
+ .Times(1);
+ EXPECT_CALL(*media_stream_manager_, StopGeneratedStream(kVideoLabel))
+ .Times(1);
+ FireVideoDeviceCallback();
+ EXPECT_EQ(static_cast<size_t>(number_audio_devices + number_video_devices),
+ host_->requested_devices().size());
+
+ EXPECT_EQ(kRequestId, host_->received_id());
+ // Check to make sure no devices have raw ids.
+ EXPECT_FALSE(DoesContainRawIds(host_->requested_devices()));
+
+ // Check to make sure every GUID produced matches a raw device id.
+ EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->requested_devices(), origin));
+ }
+
+ protected:
+ virtual ~DeviceRequestMessageFilterTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_IO));
+ io_thread_.reset(
+ new TestBrowserThread(BrowserThread::IO, message_loop_.get()));
+
+ media_stream_manager_.reset(new MockMediaStreamManager());
+ ON_CALL(*media_stream_manager_, EnumerateDevices(_, _, _, _, _, _))
+ .WillByDefault(Invoke(media_stream_manager_.get(),
+ &MockMediaStreamManager::DoEnumerateDevices));
+
+ host_ = new MockDeviceRequestMessageFilter(media_stream_manager_.get());
+ }
+
+ scoped_refptr<MockDeviceRequestMessageFilter> host_;
+ scoped_ptr<MockMediaStreamManager> media_stream_manager_;
+ StreamDeviceInfoArray physical_audio_devices_;
+ StreamDeviceInfoArray physical_video_devices_;
+ scoped_ptr<base::MessageLoop> message_loop_;
+ scoped_ptr<TestBrowserThread> io_thread_;
+
+ private:
+ void AddAudioDevices(int number_of_devices) {
+ for (int i = 0; i < number_of_devices; i++) {
+ physical_audio_devices_.push_back(
+ StreamDeviceInfo(MEDIA_DEVICE_AUDIO_CAPTURE,
+ "/dev/audio/" + base::IntToString(next_device_id_),
+ "Audio Device" + base::IntToString(next_device_id_),
+ false));
+ next_device_id_++;
+ }
+ }
+
+ void AddVideoDevices(int number_of_devices) {
+ for (int i = 0; i < number_of_devices; i++) {
+ physical_video_devices_.push_back(
+ StreamDeviceInfo(MEDIA_DEVICE_VIDEO_CAPTURE,
+ "/dev/video/" + base::IntToString(next_device_id_),
+ "Video Device" + base::IntToString(next_device_id_),
+ false));
+ next_device_id_++;
+ }
+ }
+
+ void SendGetSourcesMessage(int request_id, const GURL& origin) {
+ // Since we're not actually sending IPC messages, this is a throw-away
+ // value.
+ bool message_was_ok;
+ host_->OnMessageReceived(MediaStreamHostMsg_GetSources(request_id, origin),
+ &message_was_ok);
+ }
+
+ void FireAudioDeviceCallback() {
+ host_->DevicesEnumerated(kAudioLabel, physical_audio_devices_);
+ }
+
+ void FireVideoDeviceCallback() {
+ host_->DevicesEnumerated(kVideoLabel, physical_video_devices_);
+ }
+
+ bool DoesContainRawIds(const StreamDeviceInfoArray& devices) {
+ for (size_t i = 0; i < devices.size(); i++) {
+ for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
+ if (physical_audio_devices_[j].device.id == devices[i].device.id)
+ return true;
+ }
+ for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
+ if (physical_video_devices_[j].device.id == devices[i].device.id)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool DoesEveryDeviceMapToRawId(const StreamDeviceInfoArray& devices,
+ const GURL& origin) {
+ for (size_t i = 0; i < devices.size(); i++) {
+ bool found_match = false;
+ for (size_t j = 0; j < physical_audio_devices_.size(); ++j) {
+ if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+ origin,
+ devices[i].device.id,
+ physical_audio_devices_[j].device.id)) {
+ EXPECT_FALSE(found_match);
+ found_match = true;
+ }
+ }
+ for (size_t j = 0; j < physical_video_devices_.size(); ++j) {
+ if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+ origin,
+ devices[i].device.id,
+ physical_video_devices_[j].device.id)) {
+ EXPECT_FALSE(found_match);
+ found_match = true;
+ }
+ }
+ if (!found_match)
+ return false;
+ }
+ return true;
+ }
+
+ int next_device_id_;
+};
+
+TEST_F(DeviceRequestMessageFilterTest, TestGetSources_AudioAndVideoDevices) {
+ // Runs through test with 1 audio and 1 video device.
+ RunTest(1, 1);
+}
+
+TEST_F(DeviceRequestMessageFilterTest,
+ TestGetSources_MultipleAudioAndVideoDevices) {
+ // Runs through test with 3 audio devices and 2 video devices.
+ RunTest(3, 2);
+}
+
+TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoVideoDevices) {
+ // Runs through test with 4 audio devices and 0 video devices.
+ RunTest(4, 0);
+}
+
+TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoAudioDevices) {
+ // Runs through test with 0 audio devices and 3 video devices.
+ RunTest(0, 3);
+}
+
+TEST_F(DeviceRequestMessageFilterTest, TestGetSources_NoDevices) {
+ // Runs through test with no devices.
+ RunTest(0, 0);
+}
+
+}; // namespace content
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index ce15ee3..3e322c5 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -13,6 +13,7 @@
#include "base/rand_util.h"
#include "base/threading/thread.h"
#include "content/browser/renderer_host/media/audio_input_device_manager.h"
+#include "content/browser/renderer_host/media/device_request_message_filter.h"
#include "content/browser/renderer_host/media/media_stream_requester.h"
#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
#include "content/browser/renderer_host/media/video_capture_manager.h"
@@ -99,7 +100,7 @@ class MediaStreamManager::DeviceRequest {
// used internally within the content module.
std::string device_id =
WebContentsCaptureUtil::StripWebContentsDeviceScheme(
- request.requested_device_id);
+ request.tab_capture_device_id);
media_observer->OnMediaRequestStateChanged(
request.render_process_id, request.render_view_id,
@@ -134,6 +135,13 @@ MediaStreamManager::EnumerationCache::EnumerationCache()
MediaStreamManager::EnumerationCache::~EnumerationCache() {
}
+MediaStreamManager::MediaStreamManager()
+ : audio_manager_(NULL),
+ monitoring_started_(false),
+ io_loop_(NULL),
+ screen_capture_active_(false),
+ use_fake_ui_(false) {}
+
MediaStreamManager::MediaStreamManager(media::AudioManager* audio_manager)
: audio_manager_(audio_manager),
monitoring_started_(false),
@@ -183,8 +191,8 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Create a new request based on options.
MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id, security_origin,
- MEDIA_DEVICE_ACCESS, std::string(),
+ render_process_id, render_view_id, page_request_id, std::string(),
+ security_origin, MEDIA_DEVICE_ACCESS, std::string(), std::string(),
options.audio_type, options.video_type);
DeviceRequest* request = new DeviceRequest(NULL, stream_request);
const std::string& label = AddRequest(request);
@@ -215,7 +223,7 @@ std::string MediaStreamManager::GenerateStream(
int target_render_process_id = render_process_id;
int target_render_view_id = render_view_id;
- std::string requested_device_id;
+ std::string tab_capture_device_id;
// Customize options for a WebContents based capture.
if (options.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
@@ -223,13 +231,14 @@ std::string MediaStreamManager::GenerateStream(
// TODO(justinlin): Can't plumb audio mirroring using stream type right
// now, so plumbing by device_id. Will revisit once it's refactored.
// http://crbug.com/163100
- requested_device_id =
+ tab_capture_device_id =
WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
!options.video_device_id.empty() ?
options.video_device_id : options.audio_device_id);
bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
- requested_device_id, &target_render_process_id, &target_render_view_id);
+ tab_capture_device_id, &target_render_process_id,
+ &target_render_view_id);
if (!has_valid_device_id ||
(options.audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
options.audio_type != MEDIA_NO_SERVICE) ||
@@ -240,6 +249,22 @@ std::string MediaStreamManager::GenerateStream(
}
}
+ std::string translated_audio_device_id;
+ std::string translated_video_device_id;
+ if (options.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
+ bool found_match = TranslateGUIDToRawId(
+ MEDIA_DEVICE_AUDIO_CAPTURE, security_origin, options.audio_device_id,
+ &translated_audio_device_id);
+ DCHECK(found_match || translated_audio_device_id.empty());
+ }
+
+ if (options.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+ bool found_match = TranslateGUIDToRawId(
+ MEDIA_DEVICE_VIDEO_CAPTURE, security_origin, options.video_device_id,
+ &translated_video_device_id);
+ DCHECK(found_match || translated_video_device_id.empty());
+ }
+
if (options.video_type == MEDIA_SCREEN_VIDEO_CAPTURE) {
if (options.audio_type != MEDIA_NO_SERVICE) {
// TODO(sergeyu): Surface error message to the calling JS code.
@@ -260,7 +285,8 @@ std::string MediaStreamManager::GenerateStream(
// Create a new request based on options.
MediaStreamRequest stream_request(
target_render_process_id, target_render_view_id, page_request_id,
- security_origin, MEDIA_GENERATE_STREAM, requested_device_id,
+ tab_capture_device_id, security_origin, MEDIA_GENERATE_STREAM,
+ translated_audio_device_id, translated_video_device_id,
options.audio_type, options.video_type);
DeviceRequest* request = new DeviceRequest(requester, stream_request);
const std::string& label = AddRequest(request);
@@ -370,8 +396,8 @@ std::string MediaStreamManager::EnumerateDevices(
}
MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id, security_origin,
- MEDIA_ENUMERATE_DEVICES, std::string(),
+ render_process_id, render_view_id, page_request_id, std::string(),
+ security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(),
options.audio_type, options.video_type);
DeviceRequest* request = new DeviceRequest(requester, stream_request);
const std::string& label = AddRequest(request);
@@ -421,17 +447,19 @@ std::string MediaStreamManager::OpenDevice(
StreamOptions options;
if (IsAudioMediaType(type)) {
options.audio_type = type;
+ options.audio_device_id = device_id;
} else if (IsVideoMediaType(type)) {
options.video_type = type;
+ options.video_device_id = device_id;
} else {
NOTREACHED();
return std::string();
}
MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id, security_origin,
- MEDIA_OPEN_DEVICE, device_id,
- options.audio_type, options.video_type);
+ render_process_id, render_view_id, page_request_id, std::string(),
+ security_origin, MEDIA_OPEN_DEVICE, options.audio_device_id,
+ options.video_device_id, options.audio_type, options.video_type);
DeviceRequest* request = new DeviceRequest(requester, stream_request);
const std::string& label = AddRequest(request);
StartEnumeration(request);
@@ -479,6 +507,35 @@ void MediaStreamManager::StopMonitoring() {
}
}
+bool MediaStreamManager::TranslateGUIDToRawId(MediaStreamType stream_type,
+ const GURL& security_origin,
+ const std::string& device_guid,
+ std::string* raw_device_id) {
+ DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
+ if (device_guid.empty())
+ return false;
+
+ EnumerationCache* cache =
+ stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
+ &audio_enumeration_cache_ : &video_enumeration_cache_;
+
+ // If device monitoring hasn't started, the |device_guid| is not valid.
+ if (!cache->valid)
+ return false;
+
+ for (StreamDeviceInfoArray::const_iterator it = cache->devices.begin();
+ it != cache->devices.end();
+ ++it) {
+ if (DeviceRequestMessageFilter::DoesRawIdMatchGuid(
+ security_origin, device_guid, it->device.id)) {
+ *raw_device_id = it->device.id;
+ return true;
+ }
+ }
+ return false;
+}
+
void MediaStreamManager::ClearEnumerationCache(EnumerationCache* cache) {
DCHECK_EQ(base::MessageLoop::current(), io_loop_);
cache->valid = false;
@@ -887,7 +944,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
// Re-append the device's id since we lost it when posting request to UI.
if (device_info.device.type == content::MEDIA_TAB_VIDEO_CAPTURE ||
device_info.device.type == content::MEDIA_TAB_AUDIO_CAPTURE) {
- device_info.device.id = request->request.requested_device_id;
+ device_info.device.id = request->request.tab_capture_device_id;
// Initialize the sample_rate and channel_layout here since for audio
// mirroring, we don't go through EnumerateDevices where these are usually
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index 03d5751..6d0d2ec 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -104,7 +104,7 @@ class CONTENT_EXPORT MediaStreamManager
void CancelRequest(const std::string& label);
// Closes generated stream.
- void StopGeneratedStream(const std::string& label);
+ virtual void StopGeneratedStream(const std::string& label);
// Gets a list of devices of |type|, which must be MEDIA_DEVICE_AUDIO_CAPTURE
// or MEDIA_DEVICE_VIDEO_CAPTURE.
@@ -113,12 +113,12 @@ class CONTENT_EXPORT MediaStreamManager
// and video devices and also start monitoring device changes, such as
// plug/unplug. The new device lists will be delivered via media observer to
// MediaCaptureDevicesDispatcher.
- std::string EnumerateDevices(MediaStreamRequester* requester,
- int render_process_id,
- int render_view_id,
- int page_request_id,
- MediaStreamType type,
- const GURL& security_origin);
+ virtual std::string EnumerateDevices(MediaStreamRequester* requester,
+ int render_process_id,
+ int render_view_id,
+ int page_request_id,
+ MediaStreamType type,
+ const GURL& security_origin);
// Open a device identified by |device_id|. |type| must be either
// MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
@@ -163,6 +163,10 @@ class CONTENT_EXPORT MediaStreamManager
// case (see http://crbug.com/247525#c14).
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
+ protected:
+ // Used for testing.
+ MediaStreamManager();
+
private:
// Contains all data needed to keep track of requests.
class DeviceRequest;
@@ -213,6 +217,15 @@ class CONTENT_EXPORT MediaStreamManager
void StartMonitoring();
void StopMonitoring();
+ // Finds and returns the raw device id corresponding to the given
+ // |device_guid|. Returns true if there was a raw device id that matched the
+ // given |device_guid|, false if nothing matched it.
+ bool TranslateGUIDToRawId(
+ MediaStreamType stream_type,
+ const GURL& security_origin,
+ const std::string& device_guid,
+ std::string* raw_device_id);
+
// Device thread shared by VideoCaptureManager and AudioInputDeviceManager.
scoped_ptr<base::Thread> device_thread_;
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
index 31d69e3..4e0eff8 100644
--- a/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_proxy_unittest.cc
@@ -82,16 +82,19 @@ MATCHER_P(SameRequest, expected, "") {
return
expected.render_process_id == arg.render_process_id &&
expected.render_view_id == arg.render_view_id &&
+ expected.tab_capture_device_id == arg.tab_capture_device_id &&
expected.security_origin == arg.security_origin &&
expected.request_type == arg.request_type &&
- expected.requested_device_id == arg.requested_device_id &&
+ expected.requested_audio_device_id == arg.requested_audio_device_id &&
+ expected.requested_video_device_id == arg.requested_video_device_id &&
expected.audio_type == arg.audio_type &&
expected.video_type == arg.video_type;
}
TEST_F(MediaStreamUIProxyTest, Deny) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"),
+ MediaStreamRequest request(0, 0, 0, std::string(), GURL("http://origin/"),
MEDIA_GENERATE_STREAM, std::string(),
+ std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
MEDIA_DEVICE_VIDEO_CAPTURE);
proxy_->RequestAccess(
@@ -115,8 +118,9 @@ TEST_F(MediaStreamUIProxyTest, Deny) {
}
TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"),
+ MediaStreamRequest request(0, 0, 0, std::string(), GURL("http://origin/"),
MEDIA_GENERATE_STREAM, std::string(),
+ std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
MEDIA_DEVICE_VIDEO_CAPTURE);
proxy_->RequestAccess(
@@ -148,8 +152,9 @@ TEST_F(MediaStreamUIProxyTest, AcceptAndStart) {
// Verify that the proxy can be deleted before the request is processed.
TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"),
+ MediaStreamRequest request(0, 0, 0, std::string(), GURL("http://origin/"),
MEDIA_GENERATE_STREAM, std::string(),
+ std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
MEDIA_DEVICE_VIDEO_CAPTURE);
proxy_->RequestAccess(
@@ -169,8 +174,9 @@ TEST_F(MediaStreamUIProxyTest, DeleteBeforeAccepted) {
}
TEST_F(MediaStreamUIProxyTest, StopFromUI) {
- MediaStreamRequest request(0, 0, 0, GURL("http://origin/"),
+ MediaStreamRequest request(0, 0, 0, std::string(), GURL("http://origin/"),
MEDIA_GENERATE_STREAM, std::string(),
+ std::string(),
MEDIA_DEVICE_AUDIO_CAPTURE,
MEDIA_DEVICE_VIDEO_CAPTURE);
proxy_->RequestAccess(
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 9ea7ef9..009833d 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -73,6 +73,7 @@
#include "content/browser/renderer_host/media/audio_input_renderer_host.h"
#include "content/browser/renderer_host/media/audio_mirroring_manager.h"
#include "content/browser/renderer_host/media/audio_renderer_host.h"
+#include "content/browser/renderer_host/media/device_request_message_filter.h"
#include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
#include "content/browser/renderer_host/media/midi_host.h"
#include "content/browser/renderer_host/media/peer_connection_tracker_host.h"
@@ -644,6 +645,7 @@ void RenderProcessHostImpl::CreateMessageFilters() {
channel_->AddFilter(peer_connection_tracker_host_.get());
channel_->AddFilter(new MediaStreamDispatcherHost(
GetID(), media_stream_manager));
+ channel_->AddFilter(new DeviceRequestMessageFilter(media_stream_manager));
#endif
#if defined(ENABLE_PLUGINS)
// TODO(raymes): PepperMessageFilter should be removed from here.
@@ -887,6 +889,7 @@ void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
#endif
switches::kDisableWebAudio,
#if defined(ENABLE_WEBRTC)
+ switches::kEnableDeviceEnumeration,
switches::kEnableSCTPDataChannels,
#endif
switches::kEnableWebAnimationsCSS,
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index 8678997..a388f85 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -50,6 +50,8 @@ IPC_MESSAGE_ROUTED1(MediaStreamMsg_StreamGenerationFailed,
int /* request id */)
// The browser has enumerated devices successfully.
+// Used by Pepper.
+// TODO(vrk,wjia): Move this to pepper code.
IPC_MESSAGE_ROUTED3(MediaStreamMsg_DevicesEnumerated,
int /* request id */,
std::string /* label */,
@@ -71,6 +73,11 @@ IPC_MESSAGE_ROUTED3(MediaStreamMsg_DeviceOpened,
IPC_MESSAGE_ROUTED1(MediaStreamMsg_DeviceOpenFailed,
int /* request id */)
+// Response to enumerate devices request.
+IPC_MESSAGE_CONTROL2(MediaStreamMsg_GetSourcesACK,
+ int /* request id */,
+ content::StreamDeviceInfoArray /* device_list */)
+
// Messages sent from the renderer to the browser.
// Request a new media stream.
@@ -91,6 +98,8 @@ IPC_MESSAGE_CONTROL2(MediaStreamHostMsg_StopGeneratedStream,
std::string /* label */)
// Request to enumerate devices.
+// Used by Pepper.
+// TODO(vrk,wjia): Move this to pepper code.
IPC_MESSAGE_CONTROL4(MediaStreamHostMsg_EnumerateDevices,
int /* render view id */,
int /* request id */,
@@ -104,3 +113,8 @@ IPC_MESSAGE_CONTROL5(MediaStreamHostMsg_OpenDevice,
std::string /* device_id */,
content::MediaStreamType /* type */,
GURL /* security origin */)
+
+// Request to enumerate devices.
+IPC_MESSAGE_CONTROL2(MediaStreamHostMsg_GetSources,
+ int /* request id */,
+ GURL /* origin */)
diff --git a/content/common/media/media_stream_options.cc b/content/common/media/media_stream_options.cc
index 001fb3e..d4dec11 100644
--- a/content/common/media/media_stream_options.cc
+++ b/content/common/media/media_stream_options.cc
@@ -10,6 +10,7 @@ namespace content {
const char kMediaStreamSource[] = "chromeMediaSource";
const char kMediaStreamSourceId[] = "chromeMediaSourceId";
+const char kMediaStreamSourceInfoId[] = "sourceId";
const char kMediaStreamSourceTab[] = "tab";
const char kMediaStreamSourceScreen[] = "screen";
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index 18f0379..7e6940e 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -16,6 +16,7 @@ namespace content {
// MediaStreamConstraint keys for constraints that are passed to getUserMedia.
CONTENT_EXPORT extern const char kMediaStreamSource[];
CONTENT_EXPORT extern const char kMediaStreamSourceId[];
+CONTENT_EXPORT extern const char kMediaStreamSourceInfoId[];
CONTENT_EXPORT extern const char kMediaStreamSourceTab[];
CONTENT_EXPORT extern const char kMediaStreamSourceScreen[];
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 98ff1d4..0b7dbf1 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -790,6 +790,8 @@
'browser/renderer_host/media/audio_renderer_host.h',
'browser/renderer_host/media/audio_sync_reader.cc',
'browser/renderer_host/media/audio_sync_reader.h',
+ 'browser/renderer_host/media/device_request_message_filter.cc',
+ 'browser/renderer_host/media/device_request_message_filter.h',
'browser/renderer_host/media/media_stream_dispatcher_host.cc',
'browser/renderer_host/media/media_stream_dispatcher_host.h',
'browser/renderer_host/media/media_stream_manager.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 1c065f6..7ecf15f 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -335,6 +335,7 @@
'browser/renderer_host/media/audio_input_device_manager_unittest.cc',
'browser/renderer_host/media/audio_mirroring_manager_unittest.cc',
'browser/renderer_host/media/audio_renderer_host_unittest.cc',
+ 'browser/renderer_host/media/device_request_message_filter_unittest.cc',
'browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc',
'browser/renderer_host/media/media_stream_manager_unittest.cc',
'browser/renderer_host/media/media_stream_ui_proxy_unittest.cc',
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 7395f5b..96ddf06 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -224,6 +224,10 @@ const char kEnableWebRtcAecRecordings[] = "enable-webrtc-aec-recordings";
// Enable WebRTC DataChannels SCTP wire protocol support.
const char kEnableSCTPDataChannels[] = "enable-sctp-data-channels";
+
+// Enable WebRTC device enumeration.
+const char kEnableDeviceEnumeration[] = "enable-device-enumeration";
+
#endif
// Enable WebRTC to open TCP server sockets.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 90a7a6b..2151085 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -85,8 +85,9 @@ CONTENT_EXPORT extern const char kEnableSpeechRecognition[];
#endif
CONTENT_EXPORT extern const char kDisableWebAudio[];
#if defined(ENABLE_WEBRTC)
-extern const char kEnableWebRtcAecRecordings[];
+CONTENT_EXPORT extern const char kEnableDeviceEnumeration[];
CONTENT_EXPORT extern const char kEnableSCTPDataChannels[];
+extern const char kEnableWebRtcAecRecordings[];
extern const char kEnableWebRtcHWDecoding[];
#endif
extern const char kEnableWebRtcTcpServerSocket[];
diff --git a/content/public/common/media_stream_request.cc b/content/public/common/media_stream_request.cc
index 19f3a30..efac33f 100644
--- a/content/public/common/media_stream_request.cc
+++ b/content/public/common/media_stream_request.cc
@@ -51,17 +51,21 @@ MediaStreamRequest::MediaStreamRequest(
int render_process_id,
int render_view_id,
int page_request_id,
+ const std::string& tab_capture_device_id,
const GURL& security_origin,
MediaStreamRequestType request_type,
- const std::string& requested_device_id,
+ const std::string& requested_audio_device_id,
+ const std::string& requested_video_device_id,
MediaStreamType audio_type,
MediaStreamType video_type)
: render_process_id(render_process_id),
render_view_id(render_view_id),
page_request_id(page_request_id),
+ tab_capture_device_id(tab_capture_device_id),
security_origin(security_origin),
request_type(request_type),
- requested_device_id(requested_device_id),
+ requested_audio_device_id(requested_audio_device_id),
+ requested_video_device_id(requested_video_device_id),
audio_type(audio_type),
video_type(video_type) {
}
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index bdbc288a..0703088 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -94,14 +94,25 @@ typedef std::vector<MediaStreamDevice> MediaStreamDevices;
typedef std::map<MediaStreamType, MediaStreamDevices> MediaStreamDeviceMap;
// Represents a request for media streams (audio/video).
+// It looks like the last 4 parameters should use StreamOptions instead, but
+// StreamOption depends on media_stream_request.h because it needs
+// MediaStreamDevice.
+// TODO(vrk): Decouple MediaStreamDevice from this header file so that
+// media_stream_options.h no longer depends on this file.
+// TODO(vrk,justinlin,wjia): Figure out a way to share this code cleanly between
+// vanilla WebRTC, Tab Capture, and Pepper Video Capture. Right now there is
+// Tab-only stuff and Pepper-only stuff being passed around to all clients,
+// which is icky.
struct CONTENT_EXPORT MediaStreamRequest {
MediaStreamRequest(
int render_process_id,
int render_view_id,
int page_request_id,
+ const std::string& tab_capture_device_id,
const GURL& security_origin,
MediaStreamRequestType request_type,
- const std::string& requested_device_id,
+ const std::string& requested_audio_device_id,
+ const std::string& requested_video_device_id,
MediaStreamType audio_type,
MediaStreamType video_type);
@@ -117,6 +128,9 @@ struct CONTENT_EXPORT MediaStreamRequest {
// identifying this request. This is used for cancelling request.
int page_request_id;
+ // Used by tab capture.
+ std::string tab_capture_device_id;
+
// The WebKit security origin for the current request (e.g. "html5rocks.com").
GURL security_origin;
@@ -126,10 +140,9 @@ struct CONTENT_EXPORT MediaStreamRequest {
// Pepper requests are signified by the |MEDIA_OPEN_DEVICE| value.
MediaStreamRequestType request_type;
- // Stores the requested device id. Used only if the |request_type| filed is
- // set to |MEDIA_OPEN_DEVICE| to indicate which device the request is for as
- // in that case the decision is not left to the user but to the media client.
- std::string requested_device_id;
+ // Stores the requested raw device id for physical audio or video devices.
+ std::string requested_audio_device_id;
+ std::string requested_video_device_id;
// Flag to indicate if the request contains audio.
MediaStreamType audio_type;
diff --git a/content/renderer/media/media_stream_center.cc b/content/renderer/media/media_stream_center.cc
index 3ae7a96..7919dc5 100644
--- a/content/renderer/media/media_stream_center.cc
+++ b/content/renderer/media/media_stream_center.cc
@@ -6,10 +6,14 @@
#include <string>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "content/common/media/media_stream_messages.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/renderer/render_thread.h"
#include "content/renderer/media/media_stream_dependency_factory.h"
#include "content/renderer/media/media_stream_extra_data.h"
#include "content/renderer/media/media_stream_impl.h"
@@ -18,10 +22,15 @@
#include "third_party/WebKit/public/platform/WebMediaStreamCenterClient.h"
#include "third_party/WebKit/public/platform/WebMediaStreamSource.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
+#include "third_party/WebKit/public/platform/WebMediaStreamTrackSourcesRequest.h"
+#include "third_party/WebKit/public/platform/WebSourceInfo.h"
#include "third_party/WebKit/public/platform/WebVector.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/libjingle/source/talk/app/webrtc/jsep.h"
+using WebKit::WebFrame;
+using WebKit::WebView;
+
namespace content {
static webrtc::MediaStreamInterface* GetNativeMediaStream(
@@ -50,7 +59,21 @@ static webrtc::MediaStreamTrackInterface* GetNativeMediaStreamTrack(
MediaStreamCenter::MediaStreamCenter(WebKit::WebMediaStreamCenterClient* client,
MediaStreamDependencyFactory* factory)
- : rtc_factory_(factory) {
+ : rtc_factory_(factory), next_request_id_(0) {}
+
+MediaStreamCenter::~MediaStreamCenter() {}
+
+bool MediaStreamCenter::getMediaStreamTrackSources(
+ const WebKit::WebMediaStreamTrackSourcesRequest& request) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableDeviceEnumeration)) {
+ int request_id = next_request_id_++;
+ requests_.insert(std::make_pair(request_id, request));
+ RenderThread::Get()->Send(new MediaStreamHostMsg_GetSources(
+ request_id, GURL(request.origin().utf8())));
+ return true;
+ }
+ return false;
}
void MediaStreamCenter::didEnableMediaStreamTrack(
@@ -109,4 +132,37 @@ bool MediaStreamCenter::didRemoveMediaStreamTrack(
return rtc_factory_->RemoveNativeMediaStreamTrack(stream, track);
}
+bool MediaStreamCenter::OnControlMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(MediaStreamCenter, message)
+ IPC_MESSAGE_HANDLER(MediaStreamMsg_GetSourcesACK,
+ OnGetSourcesComplete)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void MediaStreamCenter::OnGetSourcesComplete(
+ int request_id,
+ const content::StreamDeviceInfoArray& devices) {
+ RequestMap::iterator request_it = requests_.find(request_id);
+ DCHECK(request_it != requests_.end());
+
+ WebKit::WebVector<WebKit::WebSourceInfo> sourceInfos(devices.size());
+ for (size_t i = 0; i < devices.size(); ++i) {
+ DCHECK(devices[i].device.type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ devices[i].device.type == MEDIA_DEVICE_VIDEO_CAPTURE);
+ // TODO(vrk): Hook this up to the device policy so that |device.name| is
+ // only populated when appropriate.
+ sourceInfos[i]
+ .initialize(WebKit::WebString::fromUTF8(devices[i].device.id),
+ devices[i].device.type == MEDIA_DEVICE_AUDIO_CAPTURE
+ ? WebKit::WebSourceInfo::SourceKindAudio
+ : WebKit::WebSourceInfo::SourceKindVideo,
+ WebKit::WebString::fromUTF8(devices[i].device.name),
+ WebKit::WebSourceInfo::VideoFacingModeNone);
+ }
+ request_it->second.requestSucceeded(sourceInfos);
+}
+
} // namespace content
diff --git a/content/renderer/media/media_stream_center.h b/content/renderer/media/media_stream_center.h
index aca5e53..642cda5 100644
--- a/content/renderer/media/media_stream_center.h
+++ b/content/renderer/media/media_stream_center.h
@@ -5,9 +5,13 @@
#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CENTER_H_
#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CENTER_H_
+#include <map>
+
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "content/common/content_export.h"
+#include "content/common/media/media_stream_options.h"
+#include "content/public/renderer/render_process_observer.h"
#include "third_party/WebKit/public/platform/WebMediaStream.h"
#include "third_party/WebKit/public/platform/WebMediaStreamCenter.h"
#include "third_party/WebKit/public/platform/WebMediaStreamTrack.h"
@@ -20,38 +24,57 @@ namespace content {
class MediaStreamDependencyFactory;
class CONTENT_EXPORT MediaStreamCenter
- : NON_EXPORTED_BASE(public WebKit::WebMediaStreamCenter) {
+ : NON_EXPORTED_BASE(public WebKit::WebMediaStreamCenter),
+ public RenderProcessObserver {
public:
MediaStreamCenter(WebKit::WebMediaStreamCenterClient* client,
MediaStreamDependencyFactory* factory);
+ virtual ~MediaStreamCenter();
+
+ virtual bool getMediaStreamTrackSources(
+ const WebKit::WebMediaStreamTrackSourcesRequest& request);
virtual void didEnableMediaStreamTrack(
const WebKit::WebMediaStream& stream,
- const WebKit::WebMediaStreamTrack& component) OVERRIDE;
+ const WebKit::WebMediaStreamTrack& component);
virtual void didDisableMediaStreamTrack(
const WebKit::WebMediaStream& stream,
- const WebKit::WebMediaStreamTrack& component) OVERRIDE;
+ const WebKit::WebMediaStreamTrack& component);
virtual void didStopLocalMediaStream(
- const WebKit::WebMediaStream& stream) OVERRIDE;
+ const WebKit::WebMediaStream& stream);
virtual void didCreateMediaStream(
- WebKit::WebMediaStream& stream) OVERRIDE;
+ WebKit::WebMediaStream& stream);
virtual bool didAddMediaStreamTrack(
const WebKit::WebMediaStream& stream,
- const WebKit::WebMediaStreamTrack& track) OVERRIDE;
+ const WebKit::WebMediaStreamTrack& track);
virtual bool didRemoveMediaStreamTrack(
const WebKit::WebMediaStream& stream,
- const WebKit::WebMediaStreamTrack& track) OVERRIDE;
+ const WebKit::WebMediaStreamTrack& track);
private:
+ // RenderProcessObserver implementation.
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnGetSourcesComplete(int request_id,
+ const content::StreamDeviceInfoArray& devices);
+
// |rtc_factory_| is a weak pointer and is owned by the RenderThreadImpl.
// It is valid as long as RenderThreadImpl exist.
MediaStreamDependencyFactory* rtc_factory_;
+ // A strictly increasing id that's used to label incoming GetSources()
+ // requests.
+ int next_request_id_;
+
+ typedef std::map<int, WebKit::WebMediaStreamTrackSourcesRequest> RequestMap;
+ // Maps request ids to request objects.
+ RequestMap requests_;
+
DISALLOW_COPY_AND_ASSIGN(MediaStreamCenter);
};
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
index 14fb0327..7cf1887 100644
--- a/content/renderer/media/media_stream_impl.cc
+++ b/content/renderer/media/media_stream_impl.cc
@@ -31,13 +31,18 @@
namespace content {
namespace {
-std::string GetMandatoryStreamConstraint(
- const WebKit::WebMediaConstraints& constraints, const std::string& key) {
+std::string GetStreamConstraint(
+ const WebKit::WebMediaConstraints& constraints, const std::string& key,
+ bool is_mandatory) {
if (constraints.isNull())
return std::string();
WebKit::WebString value;
- constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value);
+ if (is_mandatory) {
+ constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value);
+ } else {
+ constraints.getOptionalConstraintValue(UTF8ToUTF16(key), value);
+ }
return UTF16ToUTF8(value);
}
@@ -45,24 +50,24 @@ void UpdateRequestOptions(
const WebKit::WebUserMediaRequest& user_media_request,
StreamOptions* options) {
if (options->audio_type != content::MEDIA_NO_SERVICE) {
- std::string audio_stream_source = GetMandatoryStreamConstraint(
- user_media_request.audioConstraints(), kMediaStreamSource);
+ std::string audio_stream_source = GetStreamConstraint(
+ user_media_request.audioConstraints(), kMediaStreamSource, true);
if (audio_stream_source == kMediaStreamSourceTab) {
options->audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
- options->audio_device_id = GetMandatoryStreamConstraint(
+ options->audio_device_id = GetStreamConstraint(
user_media_request.audioConstraints(),
- kMediaStreamSourceId);
+ kMediaStreamSourceId, true);
}
}
if (options->video_type != content::MEDIA_NO_SERVICE) {
- std::string video_stream_source = GetMandatoryStreamConstraint(
- user_media_request.videoConstraints(), kMediaStreamSource);
+ std::string video_stream_source = GetStreamConstraint(
+ user_media_request.videoConstraints(), kMediaStreamSource, true);
if (video_stream_source == kMediaStreamSourceTab) {
options->video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
- options->video_device_id = GetMandatoryStreamConstraint(
+ options->video_device_id = GetStreamConstraint(
user_media_request.videoConstraints(),
- kMediaStreamSourceId);
+ kMediaStreamSourceId, true);
} else if (video_stream_source == kMediaStreamSourceScreen) {
options->video_type = content::MEDIA_SCREEN_VIDEO_CAPTURE;
}
@@ -154,10 +159,18 @@ void MediaStreamImpl::requestUserMedia(
options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
} else {
- if (user_media_request.audio())
+ if (user_media_request.audio()) {
options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
- if (user_media_request.video())
+ options.audio_device_id = GetStreamConstraint(
+ user_media_request.audioConstraints(),
+ kMediaStreamSourceInfoId, false);
+ }
+ if (user_media_request.video()) {
options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
+ options.video_device_id = GetStreamConstraint(
+ user_media_request.videoConstraints(),
+ kMediaStreamSourceInfoId, false);
+ }
security_origin = GURL(user_media_request.securityOrigin().toString());
// Get the WebFrame that requested a MediaStream.
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 31cb7bb..62a33bf 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1207,8 +1207,10 @@ WebKit::WebMediaStreamCenter* RenderThreadImpl::CreateMediaStreamCenter(
media_stream_center_ = GetContentClient()->renderer()
->OverrideCreateWebMediaStreamCenter(client);
if (!media_stream_center_) {
- media_stream_center_ = new MediaStreamCenter(
- client, GetMediaStreamDependencyFactory());
+ scoped_ptr<MediaStreamCenter> media_stream_center(
+ new MediaStreamCenter(client, GetMediaStreamDependencyFactory()));
+ AddObserver(media_stream_center.get());
+ media_stream_center_ = media_stream_center.release();
}
}
#endif