summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorperkj@chromium.org <perkj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 13:22:48 +0000
committerperkj@chromium.org <perkj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-13 13:22:48 +0000
commit1f2e3c2077babf5d8fb60180e6be3e74531ca382 (patch)
tree1e4a32da346df3e541370522880d4fc3416d9797
parent67ac6d300873e31c57c9c3b87d5b5febf28bbed8 (diff)
downloadchromium_src-1f2e3c2077babf5d8fb60180e6be3e74531ca382.zip
chromium_src-1f2e3c2077babf5d8fb60180e6be3e74531ca382.tar.gz
chromium_src-1f2e3c2077babf5d8fb60180e6be3e74531ca382.tar.bz2
This CL move all parsing of constraints used in a call to gUM from MediaStreamImpl to the MediaStreamManager.
The purpose is to be able to support all kinds of constraints when selecting what device to use. More specifically, this CL make sure that the sourceID constraint can be used as both optional and mandatory constraint. It move the parsing of what type of stream (device, tab capture or screen capture) that should be created to MediaStreamManager since that is also decided by constraints. In the end, more advanced constraints should be possible,like selecting the the camera that supports a certain resolution. BUG=325153,325692 R=hclam@chromium.org, joi@chromium.org, tommi@chromium.org, tsepez@chromium.org Review URL: https://codereview.chromium.org/102353006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@240607 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/renderer_host/media/media_stream_dispatcher_host.cc4
-rw-r--r--content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc162
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.cc578
-rw-r--r--content/browser/renderer_host/media/media_stream_manager.h24
-rw-r--r--content/browser/renderer_host/media/media_stream_manager_unittest.cc10
-rw-r--r--content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc4
-rw-r--r--content/browser/speech/speech_recognition_manager_impl.cc2
-rw-r--r--content/common/media/media_stream_messages.h15
-rw-r--r--content/common/media/media_stream_options.cc80
-rw-r--r--content/common/media/media_stream_options.h66
-rw-r--r--content/public/common/media_stream_request.h3
-rw-r--r--content/renderer/media/media_stream_dispatcher.h1
-rw-r--r--content/renderer/media/media_stream_dispatcher_unittest.cc86
-rw-r--r--content/renderer/media/media_stream_impl.cc117
-rw-r--r--content/renderer/media/mock_media_stream_dispatcher.cc8
-rw-r--r--content/renderer/media/rtc_media_constraints.cc4
16 files changed, 740 insertions, 424 deletions
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 5ce805e..05b546c 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -131,8 +131,8 @@ void MediaStreamDispatcherHost::OnGenerateStream(
DVLOG(1) << "MediaStreamDispatcherHost::OnGenerateStream("
<< render_view_id << ", "
<< page_request_id << ", ["
- << " audio:" << components.audio_type
- << " video:" << components.video_type
+ << " audio:" << components.audio_requested
+ << " video:" << components.video_requested
<< " ], "
<< security_origin.spec() << ")";
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
index 0b0ef5c..b8c4f25 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host_unittest.cc
@@ -254,10 +254,10 @@ class MediaStreamDispatcherHostTest : public testing::Test {
const StreamOptions& options) {
base::RunLoop run_loop;
int expected_audio_array_size =
- (options.audio_type != MEDIA_NO_SERVICE &&
+ (options.audio_requested &&
physical_audio_devices_.size() > 0) ? 1 : 0;
int expected_video_array_size =
- (options.video_type != MEDIA_NO_SERVICE &&
+ (options.video_requested &&
physical_video_devices_.size() > 0) ? 1 : 0;
EXPECT_CALL(*host_.get(), OnStreamGenerated(render_view_id, page_request_id,
expected_audio_array_size,
@@ -358,6 +358,12 @@ class MediaStreamDispatcherHostTest : public testing::Test {
return true;
}
+ void AddSourceIdConstraint(const std::string& source_id,
+ StreamOptions::Constraints* constraints) {
+ constraints->push_back(StreamOptions::Constraint(kMediaStreamSourceInfoId,
+ source_id));
+ }
+
scoped_refptr<MockMediaStreamDispatcherHost> host_;
scoped_ptr<media::AudioManager> audio_manager_;
scoped_ptr<MediaStreamManager> media_stream_manager_;
@@ -371,7 +377,7 @@ class MediaStreamDispatcherHostTest : public testing::Test {
};
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithVideoOnly) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -381,7 +387,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithVideoOnly) {
}
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioOnly) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_NO_SERVICE);
+ StreamOptions options(true, false);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -390,11 +396,27 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioOnly) {
EXPECT_EQ(host_->video_devices_.size(), 0u);
}
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithNothing) {
+ StreamOptions options(false, false);
+
+ GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
+}
+
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioAndVideo) {
+ StreamOptions options(true, true);
+
+ SetupFakeUI(true);
+ GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+
+ EXPECT_EQ(host_->audio_devices_.size(), 1u);
+ EXPECT_EQ(host_->video_devices_.size(), 1u);
+}
+
// This test generates two streams with video only using the same render view
// id. The same capture device with the same device and session id is expected
// to be used.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
// Generate first stream.
SetupFakeUI(true);
@@ -424,7 +446,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
TEST_F(MediaStreamDispatcherHostTest,
GenerateStreamAndOpenDeviceFromSameRenderId) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
// Generate first stream.
SetupFakeUI(true);
@@ -452,7 +474,7 @@ TEST_F(MediaStreamDispatcherHostTest,
// This test generates two streams with video only using two separate render
// view ids. The same device id but different session ids are expected.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
// Generate first stream.
SetupFakeUI(true);
@@ -484,7 +506,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
// stream to be generated before requesting the second.
// The same device id and session ids are expected.
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithoutWaiting) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
// Generate first stream.
SetupFakeUI(true);
@@ -505,74 +527,129 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithoutWaiting) {
run_loop2.Run();
}
-// Test that we can generate streams where a sourceId is specified in the
-// request.
-TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithSourceId) {
+// Test that we can generate streams where a mandatory sourceId is specified in
+// the request.
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithMandatorySourceId) {
ASSERT_GE(physical_audio_devices_.size(), 1u);
ASSERT_GE(physical_video_devices_.size(), 1u);
media::AudioDeviceNames::const_iterator audio_it =
physical_audio_devices_.begin();
for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
- options.audio_device_id = content::GetHMACForMediaDeviceID(
+ std::string source_id = content::GetHMACForMediaDeviceID(
browser_context_.GetResourceContext(),
origin_,
audio_it->unique_id);
- ASSERT_FALSE(options.audio_device_id.empty());
+ ASSERT_FALSE(source_id.empty());
+ StreamOptions options(true, true);
+ AddSourceIdConstraint(source_id, &options.mandatory_audio);
- // Generate first stream.
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
- EXPECT_EQ(host_->audio_devices_[0].device.id, options.audio_device_id);
+ EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
}
media::VideoCaptureDevice::Names::const_iterator video_it =
physical_video_devices_.begin();
for (; video_it != physical_video_devices_.end(); ++video_it) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
- options.video_device_id = content::GetHMACForMediaDeviceID(
+ std::string source_id = content::GetHMACForMediaDeviceID(
browser_context_.GetResourceContext(),
origin_,
video_it->id());
- ASSERT_FALSE(options.video_device_id.empty());
+ ASSERT_FALSE(source_id.empty());
+ StreamOptions options(true, true);
+ AddSourceIdConstraint(source_id, &options.mandatory_video);
- // Generate first stream.
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
- EXPECT_EQ(host_->video_devices_[0].device.id, options.video_device_id);
+ EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
}
}
-// Test that generating a stream with an invalid video source id fail.
-TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithInvalidVideoSourceId) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
- options.video_device_id = "invalid source id";
+// Test that we can generate streams where a optional sourceId is specified in
+// the request.
+TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithOptionalSourceId) {
+ ASSERT_GE(physical_audio_devices_.size(), 1u);
+ ASSERT_GE(physical_video_devices_.size(), 1u);
+
+ media::AudioDeviceNames::const_iterator audio_it =
+ physical_audio_devices_.begin();
+ for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
+ std::string source_id = content::GetHMACForMediaDeviceID(
+ browser_context_.GetResourceContext(),
+ origin_,
+ audio_it->unique_id);
+ ASSERT_FALSE(source_id.empty());
+ StreamOptions options(true, true);
+ AddSourceIdConstraint(source_id, &options.optional_audio);
+
+ SetupFakeUI(true);
+ GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+ EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
+ }
+
+ media::VideoCaptureDevice::Names::const_iterator video_it =
+ physical_video_devices_.begin();
+ for (; video_it != physical_video_devices_.end(); ++video_it) {
+ std::string source_id = content::GetHMACForMediaDeviceID(
+ browser_context_.GetResourceContext(),
+ origin_,
+ video_it->id());
+ ASSERT_FALSE(source_id.empty());
+ StreamOptions options(true, true);
+ AddSourceIdConstraint(source_id, &options.optional_video);
+
+ SetupFakeUI(true);
+ GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
+ EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
+ }
+}
+
+// Test that generating a stream with an invalid mandatory video source id fail.
+TEST_F(MediaStreamDispatcherHostTest,
+ GenerateStreamsWithInvalidMandatoryVideoSourceId) {
+ StreamOptions options(true, true);
+ AddSourceIdConstraint("invalid source id", &options.mandatory_video);
+
+ GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
+}
+
+// Test that generating a stream with an invalid mandatory audio source id fail.
+TEST_F(MediaStreamDispatcherHostTest,
+ GenerateStreamsWithInvalidMandatoryAudioSourceId) {
+ StreamOptions options(true, true);
+ AddSourceIdConstraint("invalid source id", &options.mandatory_audio);
+
+ GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
+}
+
+// Test that generating a stream with an invalid optional video source id
+// succeed.
+TEST_F(MediaStreamDispatcherHostTest,
+ GenerateStreamsWithInvalidOptionalVideoSourceId) {
+ StreamOptions options(true, true);
+ AddSourceIdConstraint("invalid source id", &options.optional_video);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
- EXPECT_NE(host_->video_devices_[0].device.id, options.video_device_id);
}
-// Test that generating a stream with an invalid audio source id fail.
-TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithInvalidAudioSourceId) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
- options.audio_device_id = "invalid source id";
+// Test that generating a stream with an invalid optional audio source id
+// succeed.
+TEST_F(MediaStreamDispatcherHostTest,
+ GenerateStreamsWithInvalidOptionalAudioSourceId) {
+ StreamOptions options(true, true);
+ AddSourceIdConstraint("invalid source id", &options.optional_audio);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
- EXPECT_NE(host_->audio_devices_[0].device.id, options.audio_device_id);
}
TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsNoAvailableVideoDevice) {
size_t number_of_fake_devices = physical_video_devices_.size();
media::FakeVideoCaptureDevice::SetNumberOfFakeDevices(0);
media::FakeVideoCaptureDevice::GetDeviceNames(&physical_video_devices_);
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(true, true);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -586,7 +663,7 @@ TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsNoAvailableVideoDevice) {
// been opened in a MediaStream and by pepper, the device is only stopped for
// the MediaStream.
TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStream) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -611,8 +688,7 @@ TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStream) {
}
TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStreamAndRestart) {
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(true, true);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
@@ -646,7 +722,7 @@ TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStreamAndRestart) {
}
TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
base::RunLoop run_loop;
@@ -663,7 +739,7 @@ TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
}
TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
// Create first group of streams.
size_t generated_streams = 3;
@@ -678,7 +754,7 @@ TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
}
TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(false, true);
base::Closure close_callback;
scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
@@ -701,7 +777,7 @@ TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
// being unplugged.
TEST_F(MediaStreamDispatcherHostTest, VideoDeviceUnplugged) {
size_t number_of_fake_devices = physical_video_devices_.size();
- StreamOptions options(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_DEVICE_VIDEO_CAPTURE);
+ StreamOptions options(true, true);
SetupFakeUI(true);
GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
EXPECT_EQ(host_->audio_devices_.size(), 1u);
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 2c36f31..099fb7a 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -26,6 +26,7 @@
#include "content/public/browser/media_observer.h"
#include "content/public/browser/media_request_state.h"
#include "content/public/common/content_switches.h"
+#include "content/public/common/desktop_media_id.h"
#include "content/public/common/media_stream_request.h"
#include "media/audio/audio_manager_base.h"
#include "media/audio/audio_parameters.h"
@@ -38,8 +39,9 @@
namespace content {
+namespace {
// Creates a random label used to identify requests.
-static std::string RandomLabel() {
+std::string RandomLabel() {
// An earlier PeerConnection spec,
// http://dev.w3.org/2011/webrtc/editor/webrtc.html, specified the
// MediaStream::label alphabet as containing 36 characters from
@@ -57,30 +59,135 @@ static std::string RandomLabel() {
return label;
}
-// Helper to verify if a media stream type is part of options or not.
-static bool Requested(const MediaStreamRequest& request,
- MediaStreamType stream_type) {
- return (request.audio_type == stream_type ||
- request.video_type == stream_type);
+void ParseStreamType(const StreamOptions& options,
+ MediaStreamType* audio_type,
+ MediaStreamType* video_type) {
+ *audio_type = MEDIA_NO_SERVICE;
+ *video_type = MEDIA_NO_SERVICE;
+ if (options.audio_requested) {
+ std::string audio_stream_source;
+ bool mandatory = false;
+ if (options.GetFirstAudioConstraintByName(kMediaStreamSource,
+ &audio_stream_source,
+ &mandatory)) {
+ DCHECK(mandatory);
+ // This is tab or screen capture.
+ if (audio_stream_source == kMediaStreamSourceTab) {
+ *audio_type = content::MEDIA_TAB_AUDIO_CAPTURE;
+ } else if (audio_stream_source == kMediaStreamSourceSystem) {
+ *audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE;
+ }
+ } else {
+ // This is normal audio device capture.
+ *audio_type = content::MEDIA_DEVICE_AUDIO_CAPTURE;
+ }
+ }
+ if (options.video_requested) {
+ std::string video_stream_source;
+ bool mandatory = false;
+ if (options.GetFirstVideoConstraintByName(kMediaStreamSource,
+ &video_stream_source,
+ &mandatory)) {
+ DCHECK(mandatory);
+ // This is tab or screen capture.
+ if (video_stream_source == kMediaStreamSourceTab) {
+ *video_type = content::MEDIA_TAB_VIDEO_CAPTURE;
+ } else if (video_stream_source == kMediaStreamSourceScreen) {
+ *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+ } else if (video_stream_source == kMediaStreamSourceDesktop) {
+ *video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
+ }
+ } else {
+ // This is normal video device capture.
+ *video_type = content::MEDIA_DEVICE_VIDEO_CAPTURE;
+ }
+ }
}
+} // namespace
+
+
+// MediaStreamManager::DeviceRequest represents a request to either enumerate
+// available devices or open one or more devices.
+// TODO(perkj): MediaStreamManager still needs refactoring. I propose we create
+// several subclasses of DeviceRequest and move some of the responsibility of
+// the MediaStreamManager to the subclasses to get rid of the way too many if
+// statements in MediaStreamManager.
class MediaStreamManager::DeviceRequest {
public:
DeviceRequest(MediaStreamRequester* requester,
- const MediaStreamRequest& request,
int requesting_process_id,
int requesting_view_id,
+ int page_request_id,
+ const GURL& security_origin,
+ MediaStreamRequestType request_type,
+ const StreamOptions& options,
ResourceContext* resource_context)
: requester(requester),
- request(request),
requesting_process_id(requesting_process_id),
requesting_view_id(requesting_view_id),
+ page_request_id(page_request_id),
+ security_origin(security_origin),
+ request_type(request_type),
+ options(options),
resource_context(resource_context),
- state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED) {
+ state_(NUM_MEDIA_TYPES, MEDIA_REQUEST_STATE_NOT_REQUESTED),
+ audio_type_(MEDIA_NO_SERVICE),
+ video_type_(MEDIA_NO_SERVICE) {
}
~DeviceRequest() {}
+ void SetAudioType(MediaStreamType audio_type) {
+ DCHECK(IsAudioMediaType(audio_type) || audio_type == MEDIA_NO_SERVICE);
+ audio_type_ = audio_type;
+ }
+
+ MediaStreamType audio_type() const { return audio_type_; }
+
+ void SetVideoType(MediaStreamType video_type) {
+ DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
+ video_type_ = video_type;
+ }
+
+ MediaStreamType video_type() const { return video_type_; }
+
+ // Creates a MediaStreamRequest object that is used by this request when UI
+ // is asked for permission and device selection.
+ void CreateUIRequest(const std::string& requested_audio_device_id,
+ const std::string& requested_video_device_id) {
+ DCHECK(!ui_request_);
+ ui_request_.reset(new MediaStreamRequest(requesting_process_id,
+ requesting_view_id,
+ page_request_id,
+ security_origin,
+ request_type,
+ requested_audio_device_id,
+ requested_video_device_id,
+ audio_type_,
+ video_type_));
+ }
+
+ // Creates a tab capture specific MediaStreamRequest object that is used by
+ // this request when UI is asked for permission and device selection.
+ void CreateTabCatureUIRequest(int target_render_process_id,
+ int target_render_view_id,
+ const std::string& tab_capture_id) {
+ DCHECK(!ui_request_);
+ ui_request_.reset(new MediaStreamRequest(target_render_process_id,
+ target_render_view_id,
+ page_request_id,
+ security_origin,
+ request_type,
+ "",
+ "",
+ audio_type_,
+ video_type_));
+ ui_request_->tab_capture_device_id = tab_capture_id;
+ }
+
+ const MediaStreamRequest* UIRequest() const { return ui_request_.get(); }
+
// Update the request state and notify observers.
void SetState(MediaStreamType stream_type, MediaRequestState new_state) {
if (stream_type == NUM_MEDIA_TYPES) {
@@ -97,16 +204,21 @@ class MediaStreamManager::DeviceRequest {
if (!media_observer)
return;
+ // If |ui_request_| doesn't exist, it means that the request has not yet
+ // been setup fully and there are no valid observers.
+ if (!ui_request_)
+ return;
+
// If we appended a device_id scheme, we want to remove it when notifying
// observers which may be in different modules since this scheme is only
// used internally within the content module.
std::string device_id =
WebContentsCaptureUtil::StripWebContentsDeviceScheme(
- request.tab_capture_device_id);
+ ui_request_->tab_capture_device_id);
media_observer->OnMediaRequestStateChanged(
- request.render_process_id, request.render_view_id,
- request.page_request_id,
+ ui_request_->render_process_id, ui_request_->render_view_id,
+ ui_request_->page_request_id,
MediaStreamDevice(stream_type, device_id, device_id), new_state);
}
@@ -115,7 +227,7 @@ class MediaStreamManager::DeviceRequest {
}
MediaStreamRequester* const requester; // Can be NULL.
- MediaStreamRequest request;
+
// The render process id that requested this stream to be generated and that
// will receive a handle to the MediaStream. This may be different from
@@ -129,6 +241,15 @@ class MediaStreamManager::DeviceRequest {
// specifies the target renderer from which audio and video is captured.
const int requesting_view_id;
+ // An ID the render view provided to identify this request.
+ const int page_request_id;
+
+ const GURL security_origin;
+
+ const MediaStreamRequestType request_type;
+
+ const StreamOptions options;
+
ResourceContext* resource_context;
StreamDeviceInfoArray devices;
@@ -142,6 +263,9 @@ class MediaStreamManager::DeviceRequest {
private:
std::vector<MediaRequestState> state_;
+ scoped_ptr<MediaStreamRequest> ui_request_;
+ MediaStreamType audio_type_;
+ MediaStreamType video_type_;
};
MediaStreamManager::EnumerationCache::EnumerationCache()
@@ -204,16 +328,18 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
const GURL& security_origin,
const MediaRequestResponseCallback& callback) {
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(), std::string(),
- options.audio_type, options.video_type);
+
// TODO(perkj): The argument list with NULL parameters to DeviceRequest
// suggests that this is the wrong design. Can this be refactored?
- DeviceRequest* request = new DeviceRequest(NULL, stream_request,
- render_process_id, render_view_id,
+ DeviceRequest* request = new DeviceRequest(NULL,
+ render_process_id,
+ render_view_id,
+ page_request_id,
+ security_origin,
+ MEDIA_DEVICE_ACCESS,
+ options,
NULL);
+
const std::string& label = AddRequest(request);
request->callback = callback;
@@ -232,7 +358,7 @@ std::string MediaStreamManager::MakeMediaAccessRequest(
std::string MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
int render_process_id,
int render_view_id,
- ResourceContext* rc,
+ ResourceContext* rc,
int page_request_id,
const StreamOptions& options,
const GURL& security_origin) {
@@ -247,16 +373,15 @@ std::string MediaStreamManager::GenerateStream(MediaStreamRequester* requester,
UseFakeUI(scoped_ptr<FakeMediaStreamUIProxy>());
}
- // Create a new request based on options.
- MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id,
- security_origin, MEDIA_GENERATE_STREAM,
- options.audio_device_id, options.video_device_id,
- options.audio_type, options.video_type);
- DeviceRequest* request = new DeviceRequest(requester, stream_request,
+ DeviceRequest* request = new DeviceRequest(requester,
render_process_id,
render_view_id,
+ page_request_id,
+ security_origin,
+ MEDIA_GENERATE_STREAM,
+ options,
rc);
+
const std::string& label = AddRequest(request);
// Post a task and handle the request asynchronously. The reason is that the
@@ -280,7 +405,7 @@ void MediaStreamManager::CancelRequest(const std::string& label) {
LOG(ERROR) << "The request with label = " << label << " does not exist.";
return;
}
- if (request->request.request_type == MEDIA_ENUMERATE_DEVICES) {
+ if (request->request_type == MEDIA_ENUMERATE_DEVICES) {
DeleteRequest(label);
return;
}
@@ -329,10 +454,9 @@ void MediaStreamManager::StopStreamDevice(int render_process_id,
for (DeviceRequests::iterator request_it = requests_.begin();
request_it != requests_.end(); ++request_it) {
DeviceRequest* request = request_it->second;
- const MediaStreamRequest& ms_request = request->request;
if (request->requesting_process_id != render_process_id ||
request->requesting_view_id != render_view_id ||
- ms_request.request_type != MEDIA_GENERATE_STREAM) {
+ request->request_type != MEDIA_GENERATE_STREAM) {
continue;
}
@@ -411,24 +535,19 @@ std::string MediaStreamManager::EnumerateDevices(
DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
type == MEDIA_DEVICE_VIDEO_CAPTURE);
- // Create a new request.
- StreamOptions options;
- if (type == MEDIA_DEVICE_AUDIO_CAPTURE) {
- options.audio_type = type;
- } else if (type == MEDIA_DEVICE_VIDEO_CAPTURE) {
- options.video_type = type;
- } else {
- NOTREACHED();
- return std::string();
- }
-
- MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id,
- security_origin, MEDIA_ENUMERATE_DEVICES, std::string(), std::string(),
- options.audio_type, options.video_type);
- DeviceRequest* request = new DeviceRequest(requester, stream_request,
- render_process_id, render_view_id,
+ DeviceRequest* request = new DeviceRequest(requester,
+ render_process_id,
+ render_view_id,
+ page_request_id,
+ security_origin,
+ MEDIA_ENUMERATE_DEVICES,
+ StreamOptions(),
rc);
+ if (IsAudioMediaType(type))
+ request->SetAudioType(type);
+ else if (IsVideoMediaType(type))
+ request->SetVideoType(type);
+
const std::string& label = AddRequest(request);
// Post a task and handle the request asynchronously. The reason is that the
// requester won't have a label for the request until this function returns
@@ -451,12 +570,12 @@ void MediaStreamManager::DoEnumerateDevices(const std::string& label) {
MediaStreamType type;
EnumerationCache* cache;
- if (request->request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE) {
- DCHECK_EQ(MEDIA_NO_SERVICE, request->request.video_type);
+ if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE) {
+ DCHECK_EQ(MEDIA_NO_SERVICE, request->video_type());
type = MEDIA_DEVICE_AUDIO_CAPTURE;
cache = &audio_enumeration_cache_;
} else {
- DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->request.video_type);
+ DCHECK_EQ(MEDIA_DEVICE_VIDEO_CAPTURE, request->video_type());
type = MEDIA_DEVICE_VIDEO_CAPTURE;
cache = &video_enumeration_cache_;
}
@@ -485,26 +604,28 @@ std::string MediaStreamManager::OpenDevice(
DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
type == MEDIA_DEVICE_VIDEO_CAPTURE);
- // Create a new request.
StreamOptions options;
if (IsAudioMediaType(type)) {
- options.audio_type = type;
- options.audio_device_id = device_id;
+ options.audio_requested = true;
+ options.mandatory_audio.push_back(
+ StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
} else if (IsVideoMediaType(type)) {
- options.video_type = type;
- options.video_device_id = device_id;
+ options.video_requested = true;
+ options.mandatory_video.push_back(
+ StreamOptions::Constraint(kMediaStreamSourceInfoId, device_id));
} else {
NOTREACHED();
return std::string();
}
-
- MediaStreamRequest stream_request(
- render_process_id, render_view_id, page_request_id,
- 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,
- render_process_id, render_view_id,
+ DeviceRequest* request = new DeviceRequest(requester,
+ render_process_id,
+ render_view_id,
+ page_request_id,
+ security_origin,
+ MEDIA_OPEN_DEVICE,
+ options,
rc);
+
const std::string& label = AddRequest(request);
// Post a task and handle the request asynchronously. The reason is that the
// requester won't have a label for the request until this function returns
@@ -561,7 +682,7 @@ void MediaStreamManager::StopRemovedDevice(const MediaStreamDevice& device) {
device_it != request->devices.end(); ++device_it) {
std::string source_id = content::GetHMACForMediaDeviceID(
request->resource_context,
- request->request.security_origin,
+ request->security_origin,
device.id);
if (device_it->device.id == source_id &&
device_it->device.type == device.type) {
@@ -609,56 +730,67 @@ void MediaStreamManager::StopMonitoring() {
}
}
-bool MediaStreamManager::TranslateRequestedSourceIdToDeviceId(
- DeviceRequest* request) {
- MediaStreamRequest* ms_request = &request->request;
- // If a specific device has been requested we need to find the real device id.
- if (ms_request->audio_type == MEDIA_DEVICE_AUDIO_CAPTURE &&
- !ms_request->requested_audio_device_id.empty()) {
- if (!TranslateSourceIdToDeviceId(MEDIA_DEVICE_AUDIO_CAPTURE,
- request->resource_context,
- ms_request->security_origin,
- ms_request->requested_audio_device_id,
- &ms_request->requested_audio_device_id)) {
- // TODO(perkj): gUM should support mandatory and optional constraints.
- // Ie - if the sourceId is mandatory but it does not match - gUM should
- // fail. For now we treat sourceId as an optional constraint.
- LOG(WARNING) << "Requested device does not exist.";
- ms_request->requested_audio_device_id = "";
- return true;;
- }
+bool MediaStreamManager::GetRequestedDeviceCaptureId(
+ const DeviceRequest* request,
+ MediaStreamType type,
+ std::string* device_id) const {
+ DCHECK(type == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ type == MEDIA_DEVICE_VIDEO_CAPTURE);
+ const StreamOptions::Constraints* mandatory =
+ (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
+ &request->options.mandatory_audio : &request->options.mandatory_video;
+ const StreamOptions::Constraints* optional =
+ (type == MEDIA_DEVICE_AUDIO_CAPTURE) ?
+ &request->options.optional_audio : &request->options.optional_video;
+
+ std::vector<std::string> source_ids;
+ StreamOptions::GetConstraintsByName(*mandatory,
+ kMediaStreamSourceInfoId, &source_ids);
+ if (source_ids.size() > 1) {
+ LOG(ERROR) << "Only one mandatory audio " << kMediaStreamSourceInfoId
+ << " is supported.";
+ return false;
}
-
- if (ms_request->video_type == MEDIA_DEVICE_VIDEO_CAPTURE &&
- !ms_request->requested_video_device_id.empty()) {
- if (!TranslateSourceIdToDeviceId(MEDIA_DEVICE_VIDEO_CAPTURE,
- request->resource_context,
- ms_request->security_origin,
- ms_request->requested_video_device_id,
- &ms_request->requested_video_device_id)) {
- // TODO(perkj): gUM should support mandatory and optional constraints.
- // Ie - if the sourceId is mandatory but it does not match - gUM should
- // fail. For now we treat sourceId as an optional constraint.
- LOG(WARNING) << "Requested device does not exist.";
- ms_request->requested_video_device_id = "";
- return true;
+ // If a specific device has been requested we need to find the real device
+ // id.
+ if (source_ids.size() == 1 &&
+ !TranslateSourceIdToDeviceId(type,
+ request->resource_context,
+ request->security_origin,
+ source_ids[0], device_id)) {
+ LOG(WARNING) << "Invalid mandatory audio " << kMediaStreamSourceInfoId
+ << " = " << source_ids[0] << ".";
+ return false;
+ }
+ // Check for optional audio sourceIDs.
+ if (device_id->empty()) {
+ StreamOptions::GetConstraintsByName(*optional,
+ kMediaStreamSourceInfoId,
+ &source_ids);
+ // Find the first sourceID that translates to device. Note that only one
+ // device per type can call to GenerateStream is ever opened.
+ for (std::vector<std::string>::const_iterator it = source_ids.begin();
+ it != source_ids.end(); ++it) {
+ if (TranslateSourceIdToDeviceId(type,
+ request->resource_context,
+ request->security_origin,
+ *it,
+ device_id)) {
+ break;
+ }
}
}
- DVLOG(3) << "Requested audio device "
- << ms_request->requested_audio_device_id
- << "Requested video device "
- << ms_request->requested_video_device_id;
return true;
}
void MediaStreamManager::TranslateDeviceIdToSourceId(
DeviceRequest* request,
MediaStreamDevice* device) {
- if (request->request.audio_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
- request->request.video_type == MEDIA_DEVICE_VIDEO_CAPTURE) {
+ if (request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE) {
device->id = content::GetHMACForMediaDeviceID(
request->resource_context,
- request->request.security_origin,
+ request->security_origin,
device->id);
}
}
@@ -668,12 +800,12 @@ bool MediaStreamManager::TranslateSourceIdToDeviceId(
ResourceContext* rc,
const GURL& security_origin,
const std::string& source_id,
- std::string* device_id) {
+ std::string* device_id) const {
DCHECK(stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ||
stream_type == MEDIA_DEVICE_VIDEO_CAPTURE);
DCHECK(!source_id.empty());
- EnumerationCache* cache =
+ const EnumerationCache* cache =
stream_type == MEDIA_DEVICE_AUDIO_CAPTURE ?
&audio_enumeration_cache_ : &video_enumeration_cache_;
@@ -707,15 +839,22 @@ void MediaStreamManager::StartEnumeration(DeviceRequest* request) {
}
// Start enumeration for devices of all requested device types.
- for (int i = MEDIA_NO_SERVICE + 1; i < NUM_MEDIA_TYPES; ++i) {
- const MediaStreamType stream_type = static_cast<MediaStreamType>(i);
- if (Requested(request->request, stream_type)) {
- request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED);
- DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
- if (active_enumeration_ref_count_[stream_type] == 0) {
- ++active_enumeration_ref_count_[stream_type];
- GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
- }
+ if (request->audio_type() != MEDIA_NO_SERVICE) {
+ const MediaStreamType stream_type = request->audio_type();
+ request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED);
+ DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
+ if (active_enumeration_ref_count_[stream_type] == 0) {
+ ++active_enumeration_ref_count_[stream_type];
+ GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
+ }
+ }
+ if (request->video_type() != MEDIA_NO_SERVICE) {
+ const MediaStreamType stream_type = request->video_type();
+ request->SetState(stream_type, MEDIA_REQUEST_STATE_REQUESTED);
+ DCHECK_GE(active_enumeration_ref_count_[stream_type], 0);
+ if (active_enumeration_ref_count_[stream_type] == 0) {
+ ++active_enumeration_ref_count_[stream_type];
+ GetDeviceManager(stream_type)->EnumerateDevices(stream_type);
}
}
}
@@ -749,15 +888,11 @@ void MediaStreamManager::DeleteRequest(const std::string& label) {
void MediaStreamManager::PostRequestToUI(const std::string& label,
DeviceRequest* request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(request->UIRequest());
DVLOG(1) << "PostRequestToUI({label= " << label << "})";
- // If a specific device has been requested we need to find the real device id.
- if (!TranslateRequestedSourceIdToDeviceId(request)) {
- FinalizeRequestFailed(label, request);
- return;
- }
- const MediaStreamType audio_type = request->request.audio_type;
- const MediaStreamType video_type = request->request.video_type;
+ const MediaStreamType audio_type = request->audio_type();
+ const MediaStreamType video_type = request->video_type();
// Post the request to UI and set the state.
if (IsAudioMediaType(audio_type))
@@ -793,7 +928,7 @@ void MediaStreamManager::PostRequestToUI(const std::string& label,
}
request->ui_proxy->RequestAccess(
- request->request,
+ *request->UIRequest(),
base::Bind(&MediaStreamManager::HandleAccessRequestResponse,
base::Unretained(this), label));
}
@@ -806,15 +941,18 @@ void MediaStreamManager::SetupRequest(const std::string& label) {
return; // This can happen if the request has been canceled.
}
- if (!request->request.security_origin.is_valid()) {
+ if (!request->security_origin.is_valid()) {
LOG(ERROR) << "Invalid security origin. "
- << request->request.security_origin;
+ << request->security_origin;
FinalizeRequestFailed(label, request);
return;
}
- const MediaStreamType audio_type = request->request.audio_type;
- const MediaStreamType video_type = request->request.video_type;
+ MediaStreamType audio_type = MEDIA_NO_SERVICE;
+ MediaStreamType video_type = MEDIA_NO_SERVICE;
+ ParseStreamType(request->options, &audio_type, &video_type);
+ request->SetAudioType(audio_type);
+ request->SetVideoType(video_type);
bool is_web_contents_capture =
audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
@@ -831,22 +969,64 @@ void MediaStreamManager::SetupRequest(const std::string& label) {
return;
}
- if (!is_web_contents_capture &&
- !is_screen_capture &&
- ((IsAudioMediaType(audio_type) && !audio_enumeration_cache_.valid) ||
- (IsVideoMediaType(video_type) && !video_enumeration_cache_.valid))) {
- // Enumerate the devices if there is no valid device lists to be used.
- StartEnumeration(request);
- return;
+ if (!is_web_contents_capture && !is_screen_capture) {
+ if ((!audio_enumeration_cache_.valid && IsAudioMediaType(audio_type)) ||
+ (!video_enumeration_cache_.valid && IsVideoMediaType(video_type))) {
+ // Enumerate the devices if there is no valid device lists to be used.
+ StartEnumeration(request);
+ return;
+ }
+ if (!SetupDeviceCaptureRequest(request)) {
+ FinalizeRequestFailed(label, request);
+ return;
+ }
}
PostRequestToUI(label, request);
}
+bool MediaStreamManager::SetupDeviceCaptureRequest(DeviceRequest* request) {
+ DCHECK((request->audio_type() == MEDIA_DEVICE_AUDIO_CAPTURE ||
+ request->audio_type() == MEDIA_NO_SERVICE) &&
+ (request->video_type() == MEDIA_DEVICE_VIDEO_CAPTURE ||
+ request->video_type() == MEDIA_NO_SERVICE));
+ std::string audio_device_id;
+ if (request->options.audio_requested &&
+ !GetRequestedDeviceCaptureId(request, request->audio_type(),
+ &audio_device_id)) {
+ return false;
+ }
+
+ std::string video_device_id;
+ if (request->options.video_requested &&
+ !GetRequestedDeviceCaptureId(request, request->video_type(),
+ &video_device_id)) {
+ return false;
+ }
+ request->CreateUIRequest(audio_device_id, video_device_id);
+ DVLOG(3) << "Audio requested " << request->options.audio_requested
+ << " device id = " << audio_device_id
+ << "Video requested " << request->options.video_requested
+ << " device id = " << video_device_id;
+ return true;
+}
+
bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
- DCHECK(request->request.audio_type == MEDIA_TAB_AUDIO_CAPTURE ||
- request->request.video_type == MEDIA_TAB_VIDEO_CAPTURE);
+ DCHECK(request->audio_type() == MEDIA_TAB_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_TAB_VIDEO_CAPTURE);
+
+ std::string capture_device_id;
+ bool mandatory_audio = false;
+ bool mandatory_video = false;
+ if (!request->options.GetFirstAudioConstraintByName(kMediaStreamSourceId,
+ &capture_device_id,
+ &mandatory_audio) &&
+ !request->options.GetFirstVideoConstraintByName(kMediaStreamSourceId,
+ &capture_device_id,
+ &mandatory_video)) {
+ return false;
+ }
+ DCHECK(mandatory_audio || mandatory_video);
- MediaStreamRequest* ms_request = &request->request;
// Customize options for a WebContents based capture.
int target_render_process_id = 0;
int target_render_view_id = 0;
@@ -855,24 +1035,23 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
// now, so plumbing by device_id. Will revisit once it's refactored.
// http://crbug.com/163100
std::string tab_capture_device_id =
- WebContentsCaptureUtil::AppendWebContentsDeviceScheme(
- !ms_request->requested_video_device_id.empty() ?
- ms_request->requested_video_device_id :
- ms_request->requested_audio_device_id);
+ WebContentsCaptureUtil::AppendWebContentsDeviceScheme(capture_device_id);
bool has_valid_device_id = WebContentsCaptureUtil::ExtractTabCaptureTarget(
tab_capture_device_id, &target_render_process_id,
&target_render_view_id);
if (!has_valid_device_id ||
- (ms_request->audio_type != MEDIA_TAB_AUDIO_CAPTURE &&
- ms_request->audio_type != MEDIA_NO_SERVICE) ||
- (ms_request->video_type != MEDIA_TAB_VIDEO_CAPTURE &&
- ms_request->video_type != MEDIA_NO_SERVICE)) {
+ (request->audio_type() != MEDIA_TAB_AUDIO_CAPTURE &&
+ request->audio_type() != MEDIA_NO_SERVICE) ||
+ (request->video_type() != MEDIA_TAB_VIDEO_CAPTURE &&
+ request->video_type() != MEDIA_NO_SERVICE)) {
return false;
}
- ms_request->tab_capture_device_id = tab_capture_device_id;
- ms_request->render_process_id = target_render_process_id;
- ms_request->render_view_id = target_render_view_id;
+
+ request->CreateTabCatureUIRequest(target_render_process_id,
+ target_render_view_id,
+ tab_capture_device_id);
+
DVLOG(3) << "SetupTabCaptureRequest "
<< ", {tab_capture_device_id = " << tab_capture_device_id << "}"
<< ", {target_render_process_id = " << target_render_process_id
@@ -882,20 +1061,48 @@ bool MediaStreamManager::SetupTabCaptureRequest(DeviceRequest* request) {
}
bool MediaStreamManager::SetupScreenCaptureRequest(DeviceRequest* request) {
- DCHECK(request->request.audio_type == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
- request->request.video_type == MEDIA_DESKTOP_VIDEO_CAPTURE);
- const MediaStreamRequest& ms_request = request->request;
+ DCHECK(request->audio_type() == MEDIA_LOOPBACK_AUDIO_CAPTURE ||
+ request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE);
// For screen capture we only support two valid combinations:
// (1) screen video capture only, or
// (2) screen video capture with loopback audio capture.
- if (ms_request.video_type != MEDIA_DESKTOP_VIDEO_CAPTURE ||
- (ms_request.audio_type != MEDIA_NO_SERVICE &&
- ms_request.audio_type != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
- // TODO(sergeyu): Surface error message to the calling JS code.
+ if (request->video_type() != MEDIA_DESKTOP_VIDEO_CAPTURE ||
+ (request->audio_type() != MEDIA_NO_SERVICE &&
+ request->audio_type() != MEDIA_LOOPBACK_AUDIO_CAPTURE)) {
LOG(ERROR) << "Invalid screen capture request.";
return false;
}
+
+ std::string video_device_id;
+ if (request->video_type() == MEDIA_DESKTOP_VIDEO_CAPTURE) {
+ std::string video_stream_source;
+ bool mandatory = false;
+ if (!request->options.GetFirstVideoConstraintByName(
+ kMediaStreamSource,
+ &video_stream_source,
+ &mandatory)) {
+ LOG(ERROR) << kMediaStreamSource << " not found.";
+ return false;
+ }
+ DCHECK(mandatory);
+
+ if (video_stream_source == kMediaStreamSourceScreen) {
+ video_device_id =
+ DesktopMediaID(DesktopMediaID::TYPE_SCREEN, 0).ToString();
+ } else if (video_stream_source == kMediaStreamSourceDesktop) {
+ if (!request->options.GetFirstVideoConstraintByName(
+ kMediaStreamSourceId,
+ &video_device_id,
+ &mandatory)) {
+ LOG(ERROR) << kMediaStreamSourceId << " not found.";
+ return false;
+ }
+ DCHECK(mandatory);
+ }
+ }
+
+ request->CreateUIRequest("", video_device_id);
return true;
}
@@ -915,11 +1122,9 @@ bool MediaStreamManager::FindExistingRequestedDeviceInfo(
DCHECK(existing_device_info);
DCHECK(existing_request_state);
- const MediaStreamRequest& new_ms_request = new_request.request;
-
std::string source_id = content::GetHMACForMediaDeviceID(
new_request.resource_context,
- new_ms_request.security_origin,
+ new_request.security_origin,
new_device_info.id);
for (DeviceRequests::const_iterator it = requests_.begin();
@@ -927,7 +1132,7 @@ bool MediaStreamManager::FindExistingRequestedDeviceInfo(
const DeviceRequest* request = it->second;
if (request->requesting_process_id == new_request.requesting_process_id &&
request->requesting_view_id == new_request.requesting_view_id &&
- request->request.request_type == new_ms_request.request_type) {
+ request->request_type == new_request.request_type) {
for (StreamDeviceInfoArray::const_iterator device_it =
request->devices.begin();
device_it != request->devices.end(); ++device_it) {
@@ -971,7 +1176,7 @@ void MediaStreamManager::FinalizeRequestFailed(
if (request->requester)
request->requester->StreamGenerationFailed(label);
- if (request->request.request_type == MEDIA_DEVICE_ACCESS &&
+ if (request->request_type == MEDIA_DEVICE_ACCESS &&
!request->callback.is_null()) {
request->callback.Run(MediaStreamDevices(), request->ui_proxy.Pass());
}
@@ -987,7 +1192,7 @@ void MediaStreamManager::FinalizeOpenDevice(const std::string& label,
void MediaStreamManager::FinalizeEnumerateDevices(const std::string& label,
DeviceRequest* request) {
- if (!request->request.security_origin.is_valid()) {
+ if (!request->security_origin.is_valid()) {
request->requester->DevicesEnumerated(label, StreamDeviceInfoArray());
return;
}
@@ -1082,7 +1287,7 @@ void MediaStreamManager::HandleRequestDone(const std::string& label,
DVLOG(1) << "HandleRequestDone("
<< ", {label = " << label << "})";
- switch (request->request.request_type) {
+ switch (request->request_type) {
case MEDIA_OPEN_DEVICE:
FinalizeOpenDevice(label, request);
break;
@@ -1144,8 +1349,9 @@ void MediaStreamManager::DevicesEnumerated(
for (DeviceRequests::iterator it = requests_.begin(); it != requests_.end();
++it) {
if (it->second->state(stream_type) == MEDIA_REQUEST_STATE_REQUESTED &&
- Requested(it->second->request, stream_type)) {
- if (it->second->request.request_type != MEDIA_ENUMERATE_DEVICES)
+ (it->second->audio_type() == stream_type ||
+ it->second->video_type() == stream_type)) {
+ if (it->second->request_type != MEDIA_ENUMERATE_DEVICES)
it->second->SetState(stream_type, MEDIA_REQUEST_STATE_PENDING_APPROVAL);
label_list.push_back(it->first);
}
@@ -1153,7 +1359,7 @@ void MediaStreamManager::DevicesEnumerated(
for (std::list<std::string>::iterator it = label_list.begin();
it != label_list.end(); ++it) {
DeviceRequest* request = FindRequest(*it);
- switch (request->request.request_type) {
+ switch (request->request_type) {
case MEDIA_ENUMERATE_DEVICES:
if (need_update_clients && request->requester) {
request->devices = devices;
@@ -1161,17 +1367,19 @@ void MediaStreamManager::DevicesEnumerated(
}
break;
default:
- if (request->state(request->request.audio_type) ==
+ if (request->state(request->audio_type()) ==
MEDIA_REQUEST_STATE_REQUESTED ||
- request->state(request->request.video_type) ==
+ request->state(request->video_type()) ==
MEDIA_REQUEST_STATE_REQUESTED) {
// We are doing enumeration for other type of media, wait until it is
// all done before posting the request to UI because UI needs
// the device lists to handle the request.
break;
}
-
- PostRequestToUI(*it, request);
+ if (!SetupDeviceCaptureRequest(request))
+ FinalizeRequestFailed(*it, request);
+ else
+ PostRequestToUI(*it, request);
break;
}
}
@@ -1193,7 +1401,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
return;
}
- if (request->request.request_type == MEDIA_DEVICE_ACCESS) {
+ if (request->request_type == MEDIA_DEVICE_ACCESS) {
FinalizeMediaAccessRequest(label, request, devices);
return;
}
@@ -1216,7 +1424,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.tab_capture_device_id;
+ device_info.device.id = request->UIRequest()->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
@@ -1235,9 +1443,9 @@ void MediaStreamManager::HandleAccessRequestResponse(
}
}
- if (device_info.device.type == request->request.audio_type) {
+ if (device_info.device.type == request->audio_type()) {
found_audio = true;
- } else if (device_info.device.type == request->request.video_type) {
+ } else if (device_info.device.type == request->video_type()) {
found_video = true;
}
@@ -1245,7 +1453,7 @@ void MediaStreamManager::HandleAccessRequestResponse(
// per render view. This is so that the permission to use a device can be
// revoked by a single call to StopStreamDevice regardless of how many
// MediaStreams it is being used in.
- if (request->request.request_type == MEDIA_GENERATE_STREAM) {
+ if (request->request_type == MEDIA_GENERATE_STREAM) {
MediaRequestState state;
if (FindExistingRequestedDeviceInfo(*request,
device_info.device,
@@ -1272,13 +1480,13 @@ void MediaStreamManager::HandleAccessRequestResponse(
}
// Check whether we've received all stream types requested.
- if (!found_audio && IsAudioMediaType(request->request.audio_type)) {
- request->SetState(request->request.audio_type, MEDIA_REQUEST_STATE_ERROR);
+ if (!found_audio && IsAudioMediaType(request->audio_type())) {
+ request->SetState(request->audio_type(), MEDIA_REQUEST_STATE_ERROR);
DVLOG(1) << "Set no audio found label " << label;
}
- if (!found_video && IsVideoMediaType(request->request.video_type))
- request->SetState(request->request.video_type, MEDIA_REQUEST_STATE_ERROR);
+ if (!found_video && IsVideoMediaType(request->video_type()))
+ request->SetState(request->video_type(), MEDIA_REQUEST_STATE_ERROR);
if (RequestDone(*request))
HandleRequestDone(label, request);
@@ -1360,24 +1568,20 @@ void MediaStreamManager::NotifyDevicesChanged(
bool MediaStreamManager::RequestDone(const DeviceRequest& request) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- const bool requested_audio = IsAudioMediaType(request.request.audio_type);
- const bool requested_video = IsVideoMediaType(request.request.video_type);
+ const bool requested_audio = IsAudioMediaType(request.audio_type());
+ const bool requested_video = IsVideoMediaType(request.video_type());
const bool audio_done =
!requested_audio ||
- request.state(request.request.audio_type) ==
- MEDIA_REQUEST_STATE_DONE ||
- request.state(request.request.audio_type) ==
- MEDIA_REQUEST_STATE_ERROR;
+ request.state(request.audio_type()) == MEDIA_REQUEST_STATE_DONE ||
+ request.state(request.audio_type()) == MEDIA_REQUEST_STATE_ERROR;
if (!audio_done)
return false;
const bool video_done =
!requested_video ||
- request.state(request.request.video_type) ==
- MEDIA_REQUEST_STATE_DONE ||
- request.state(request.request.video_type) ==
- MEDIA_REQUEST_STATE_ERROR;
+ request.state(request.video_type()) == MEDIA_REQUEST_STATE_DONE ||
+ request.state(request.video_type()) == MEDIA_REQUEST_STATE_ERROR;
if (!video_done)
return false;
diff --git a/content/browser/renderer_host/media/media_stream_manager.h b/content/browser/renderer_host/media/media_stream_manager.h
index db99cd5..6d14cb5 100644
--- a/content/browser/renderer_host/media/media_stream_manager.h
+++ b/content/browser/renderer_host/media/media_stream_manager.h
@@ -86,7 +86,7 @@ class CONTENT_EXPORT MediaStreamManager
int render_process_id,
int render_view_id,
int page_request_id,
- const StreamOptions& components,
+ const StreamOptions& options,
const GURL& security_origin,
const MediaRequestResponseCallback& callback);
@@ -236,11 +236,20 @@ class CONTENT_EXPORT MediaStreamManager
// Prepare the request with label |label| by starting device enumeration if
// needed.
void SetupRequest(const std::string& label);
+ // Prepare |request| of type MEDIA_DEVICE_AUDIO_CAPTURE and/or
+ // MEDIA_DEVICE_VIDEO_CAPTURE for being posted to the UI by parsing
+ // StreamOptions::Constraints for requested device IDs.
+ bool SetupDeviceCaptureRequest(DeviceRequest* request);
+ // Prepare |request| of type MEDIA_TAB_AUDIO_CAPTURE and/or
+ // MEDIA_TAB_VIDEO_CAPTURE for being posted to the UI by parsing
+ // StreamOptions::Constraints for requested tab capture IDs.
bool SetupTabCaptureRequest(DeviceRequest* request);
+ // Prepare |request| of type MEDIA_LOOPBACK_AUDIO_CAPTURE and/or
+ // MEDIA_DESKTOP_VIDEO_CAPTURE for being posted to the UI by parsing
+ // StreamOptions::Constraints for the requested desktop ID.
bool SetupScreenCaptureRequest(DeviceRequest* request);
// Called when a request has been setup and devices have been enumerated if
- // needed. If a certain source id has been requested, the source id is
- // translated to a real device id before the request is posted to UI.
+ // needed.
void PostRequestToUI(const std::string& label, DeviceRequest* request);
// Returns true if a device with |device_id| has already been requested with
// a render procecss_id and render_view_id and type equal to the the values
@@ -279,7 +288,12 @@ class CONTENT_EXPORT MediaStreamManager
void StartMonitoring();
void StopMonitoring();
- bool TranslateRequestedSourceIdToDeviceId(DeviceRequest* request);
+ // Finds the requested device id from constraints. The requested device type
+ // must be MEDIA_DEVICE_AUDIO_CAPTURE or MEDIA_DEVICE_VIDEO_CAPTURE.
+ bool GetRequestedDeviceCaptureId(const DeviceRequest* request,
+ MediaStreamType type,
+ std::string* device_id) const;
+
void TranslateDeviceIdToSourceId(DeviceRequest* request,
MediaStreamDevice* device);
@@ -291,7 +305,7 @@ class CONTENT_EXPORT MediaStreamManager
ResourceContext* rc,
const GURL& security_origin,
const std::string& source_id,
- std::string* device_id);
+ std::string* device_id) const;
// Device thread shared by VideoCaptureManager and AudioInputDeviceManager.
scoped_ptr<base::Thread> device_thread_;
diff --git a/content/browser/renderer_host/media/media_stream_manager_unittest.cc b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
index f4f0b20..be4d498 100644
--- a/content/browser/renderer_host/media/media_stream_manager_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_manager_unittest.cc
@@ -99,16 +99,15 @@ class MediaStreamManagerTest : public ::testing::Test {
const int render_process_id = 1;
const int render_view_id = 1;
const int page_request_id = 1;
- StreamOptions components(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
const GURL security_origin;
MediaStreamManager::MediaRequestResponseCallback callback =
base::Bind(&MediaStreamManagerTest::ResponseCallback,
base::Unretained(this), index);
+ StreamOptions options(true, true);
return media_stream_manager_->MakeMediaAccessRequest(render_process_id,
render_view_id,
page_request_id,
- components,
+ options,
security_origin,
callback);
}
@@ -147,9 +146,8 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) {
int render_process_id = 2;
int render_view_id = 2;
int page_request_id = 2;
- StreamOptions components(MEDIA_DEVICE_AUDIO_CAPTURE,
- MEDIA_DEVICE_VIDEO_CAPTURE);
GURL security_origin;
+ StreamOptions options(true, true);
MediaStreamManager::MediaRequestResponseCallback callback =
base::Bind(&MediaStreamManagerTest::ResponseCallback,
base::Unretained(this), 1);
@@ -157,7 +155,7 @@ TEST_F(MediaStreamManagerTest, MakeMultipleRequests) {
render_process_id,
render_view_id,
page_request_id,
- components,
+ options,
security_origin,
callback);
diff --git a/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc b/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
index 00a2cc2..f65936e 100644
--- a/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
+++ b/content/browser/renderer_host/media/media_stream_ui_controller_unittest.cc
@@ -58,9 +58,7 @@ class MediaStreamDeviceUIControllerTest
void CreateDummyRequest(const std::string& label, bool audio, bool video) {
int dummy_render_process_id = 1;
int dummy_render_view_id = 1;
- StreamOptions components(
- audio ? MEDIA_DEVICE_AUDIO_CAPTURE : MEDIA_NO_SERVICE,
- video ? MEDIA_DEVICE_VIDEO_CAPTURE : MEDIA_NO_SERVICE);
+ StreamOptions components(audio, video );
GURL security_origin;
ui_controller_->MakeUIRequest(label,
dummy_render_process_id,
diff --git a/content/browser/speech/speech_recognition_manager_impl.cc b/content/browser/speech/speech_recognition_manager_impl.cc
index 6ecfa70..9602374 100644
--- a/content/browser/speech/speech_recognition_manager_impl.cc
+++ b/content/browser/speech/speech_recognition_manager_impl.cc
@@ -197,7 +197,7 @@ void SpeechRecognitionManagerImpl::RecognitionAllowedCallback(int session_id,
context.render_process_id,
context.render_view_id,
context.request_id,
- StreamOptions(MEDIA_DEVICE_AUDIO_CAPTURE, MEDIA_NO_SERVICE),
+ StreamOptions(true, false),
GURL(context.context_name),
base::Bind(
&SpeechRecognitionManagerImpl::MediaRequestPermissionCallback,
diff --git a/content/common/media/media_stream_messages.h b/content/common/media/media_stream_messages.h
index c6e44a2..2b78617 100644
--- a/content/common/media/media_stream_messages.h
+++ b/content/common/media/media_stream_messages.h
@@ -22,11 +22,18 @@ IPC_ENUM_TRAITS_MAX_VALUE(content::MediaStreamType,
IPC_ENUM_TRAITS_MAX_VALUE(content::VideoFacingMode,
content::NUM_MEDIA_VIDEO_FACING_MODE - 1)
+IPC_STRUCT_TRAITS_BEGIN(content::StreamOptions::Constraint)
+ IPC_STRUCT_TRAITS_MEMBER(name)
+ IPC_STRUCT_TRAITS_MEMBER(value)
+IPC_STRUCT_TRAITS_END()
+
IPC_STRUCT_TRAITS_BEGIN(content::StreamOptions)
- IPC_STRUCT_TRAITS_MEMBER(audio_type)
- IPC_STRUCT_TRAITS_MEMBER(audio_device_id)
- IPC_STRUCT_TRAITS_MEMBER(video_type)
- IPC_STRUCT_TRAITS_MEMBER(video_device_id)
+ IPC_STRUCT_TRAITS_MEMBER(audio_requested)
+ IPC_STRUCT_TRAITS_MEMBER(mandatory_audio)
+ IPC_STRUCT_TRAITS_MEMBER(optional_audio)
+ IPC_STRUCT_TRAITS_MEMBER(video_requested)
+ IPC_STRUCT_TRAITS_MEMBER(mandatory_video)
+ IPC_STRUCT_TRAITS_MEMBER(optional_video)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(content::StreamDeviceInfo)
diff --git a/content/common/media/media_stream_options.cc b/content/common/media/media_stream_options.cc
index ef5a9da..4ddef01 100644
--- a/content/common/media/media_stream_options.cc
+++ b/content/common/media/media_stream_options.cc
@@ -18,15 +18,79 @@ const char kMediaStreamSourceSystem[] = "system";
const char kMediaStreamRenderToAssociatedSink[] =
"chromeRenderToAssociatedSink";
+namespace {
+
+bool GetFirstConstraintByName(const StreamOptions::Constraints& constraints,
+ const std::string& name,
+ std::string* value) {
+ for (StreamOptions::Constraints::const_iterator it = constraints.begin();
+ it != constraints.end(); ++it ) {
+ if (it->name == name) {
+ *value = it->value;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GetFirstConstraintByName(const StreamOptions::Constraints& mandatory,
+ const StreamOptions::Constraints& optional,
+ const std::string& name,
+ std::string* value,
+ bool* is_mandatory) {
+ if (GetFirstConstraintByName(mandatory, name, value)) {
+ if (is_mandatory)
+ *is_mandatory = true;
+ return true;
+ }
+ if (is_mandatory)
+ *is_mandatory = false;
+ return GetFirstConstraintByName(optional, name, value);
+}
+
+} // namespace
+
StreamOptions::StreamOptions()
- : audio_type(MEDIA_NO_SERVICE),
- video_type(MEDIA_NO_SERVICE) {}
-
-StreamOptions::StreamOptions(MediaStreamType audio_type,
- MediaStreamType video_type)
- : audio_type(audio_type), video_type(video_type) {
- DCHECK(IsAudioMediaType(audio_type) || audio_type == MEDIA_NO_SERVICE);
- DCHECK(IsVideoMediaType(video_type) || video_type == MEDIA_NO_SERVICE);
+ : audio_requested(false),
+ video_requested(false) {}
+
+StreamOptions::StreamOptions(bool request_audio, bool request_video)
+ : audio_requested(request_audio), video_requested(request_video) {
+}
+
+StreamOptions::~StreamOptions() {}
+
+StreamOptions::Constraint::Constraint() {}
+
+StreamOptions::Constraint::Constraint(const std::string& name,
+ const std::string& value)
+ : name(name), value(value) {
+}
+
+bool StreamOptions::GetFirstAudioConstraintByName(const std::string& name,
+ std::string* value,
+ bool* is_mandatory) const {
+ return GetFirstConstraintByName(mandatory_audio, optional_audio, name, value,
+ is_mandatory);
+}
+
+bool StreamOptions::GetFirstVideoConstraintByName(const std::string& name,
+ std::string* value,
+ bool* is_mandatory) const {
+ return GetFirstConstraintByName(mandatory_video, optional_video, name, value,
+ is_mandatory);
+}
+
+// static
+void StreamOptions::GetConstraintsByName(
+ const StreamOptions::Constraints& constraints,
+ const std::string& name,
+ std::vector<std::string>* values) {
+ for (StreamOptions::Constraints::const_iterator it = constraints.begin();
+ it != constraints.end(); ++it ) {
+ if (it->name == name)
+ values->push_back(it->value);
+ }
}
// static
diff --git a/content/common/media/media_stream_options.h b/content/common/media/media_stream_options.h
index e48aed1..1b7401c 100644
--- a/content/common/media/media_stream_options.h
+++ b/content/common/media/media_stream_options.h
@@ -28,20 +28,60 @@ CONTENT_EXPORT extern const char kMediaStreamSourceSystem[];
// device belongs to.
CONTENT_EXPORT extern const char kMediaStreamRenderToAssociatedSink[];
-// StreamOptions is a Chromium representation of WebKit's
-// WebUserMediaRequest Options. It describes the components
-// in a request for a new media stream.
-struct CONTENT_EXPORT StreamOptions {
+// StreamOptions is a Chromium representation of constraints
+// used in WebUserMediaRequest.
+// It describes properties requested by JS in a request for a new
+// media stream.
+class CONTENT_EXPORT StreamOptions {
+ public:
StreamOptions();
- StreamOptions(MediaStreamType audio_type, MediaStreamType video_type);
-
- // If not NO_SERVICE, the stream shall contain an audio input stream.
- MediaStreamType audio_type;
- std::string audio_device_id;
-
- // If not NO_SERVICE, the stream shall contain a video input stream.
- MediaStreamType video_type;
- std::string video_device_id;
+ StreamOptions(bool request_audio, bool request_video);
+ ~StreamOptions();
+
+ struct CONTENT_EXPORT Constraint {
+ Constraint();
+ Constraint(const std::string& name,
+ const std::string& value);
+
+ std::string name;
+ std::string value;
+ };
+ typedef std::vector<Constraint> Constraints;
+
+ bool audio_requested;
+ Constraints mandatory_audio;
+ Constraints optional_audio;
+
+ bool video_requested;
+ Constraints mandatory_video;
+ Constraints optional_video;
+
+ // Fetches |value| from the first audio constraint with a name that matches
+ // |name| from |mandatory_audio| and |optional_audio|. First mandatory
+ // constraints are searched, then optional.
+ // |is_mandatory| may be NULL but if it is provided, it is set
+ // to true if the found constraint is mandatory.
+ // Returns false if no constraint is found.
+ bool GetFirstAudioConstraintByName(const std::string& name,
+ std::string* value,
+ bool* is_mandatory) const;
+
+ // Fetches |value| from the first video constraint with a name that matches
+ // |name| from |mandatory_video| and |optional_video|. First mandatory
+ // constraints are searched, then optional.
+ // |is_mandatory| may be NULL but if it is provided, it is set
+ // to true if the found constraint is mandatory.
+ // Returns false if no constraint is found.
+ bool GetFirstVideoConstraintByName(const std::string& name,
+ std::string* value,
+ bool* is_mandatory) const;
+
+ // Fetches |values| from all constraint with a name that matches |name|
+ // from |constraints|.
+ static void GetConstraintsByName(
+ const StreamOptions::Constraints& constraints,
+ const std::string& name,
+ std::vector<std::string>* values);
};
// StreamDeviceInfo describes information about a device.
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index e6870e1..6e42920 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -149,9 +149,6 @@ 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
diff --git a/content/renderer/media/media_stream_dispatcher.h b/content/renderer/media/media_stream_dispatcher.h
index f354007..89d7c0d 100644
--- a/content/renderer/media/media_stream_dispatcher.h
+++ b/content/renderer/media/media_stream_dispatcher.h
@@ -95,7 +95,6 @@ class CONTENT_EXPORT MediaStreamDispatcher
int GetNextIpcIdForTest() { return next_ipc_id_; }
private:
- FRIEND_TEST_ALL_PREFIXES(MediaStreamDispatcherTest, BasicStreamForDevice);
FRIEND_TEST_ALL_PREFIXES(MediaStreamDispatcherTest, BasicVideoDevice);
FRIEND_TEST_ALL_PREFIXES(MediaStreamDispatcherTest, TestFailure);
FRIEND_TEST_ALL_PREFIXES(MediaStreamDispatcherTest, CancelGenerateStream);
diff --git a/content/renderer/media/media_stream_dispatcher_unittest.cc b/content/renderer/media/media_stream_dispatcher_unittest.cc
index b34664f..635d22f 100644
--- a/content/renderer/media/media_stream_dispatcher_unittest.cc
+++ b/content/renderer/media/media_stream_dispatcher_unittest.cc
@@ -28,7 +28,6 @@ const int kRequestId4 = 40;
const MediaStreamType kAudioType = MEDIA_DEVICE_AUDIO_CAPTURE;
const MediaStreamType kVideoType = MEDIA_DEVICE_VIDEO_CAPTURE;
-const MediaStreamType kNoAudioType = MEDIA_NO_SERVICE;
class MockMediaStreamDispatcherEventHandler
: public MediaStreamDispatcherEventHandler,
@@ -134,9 +133,8 @@ class MediaStreamDispatcherTest : public ::testing::Test {
// the id returned by GenerateStream.
std::string CompleteGenerateStream(int ipc_id, const StreamOptions& options,
int request_id) {
- bool audio_available = options.audio_type;
- StreamDeviceInfoArray audio_device_array(audio_available ? 1 : 0);
- if (audio_available) {
+ StreamDeviceInfoArray audio_device_array(options.audio_requested ? 1 : 0);
+ if (options.audio_requested) {
StreamDeviceInfo audio_device_info;
audio_device_info.device.name = "Microphone";
audio_device_info.device.type = kAudioType;
@@ -144,9 +142,8 @@ class MediaStreamDispatcherTest : public ::testing::Test {
audio_device_array[0] = audio_device_info;
}
- bool video_available = options.video_type;
- StreamDeviceInfoArray video_device_array(video_available ? 1 : 0);
- if (video_available) {
+ StreamDeviceInfoArray video_device_array(options.video_requested ? 1 : 0);
+ if (options.video_requested) {
StreamDeviceInfo video_device_info;
video_device_info.device.name = "Camera";
video_device_info.device.type = kVideoType;
@@ -164,10 +161,10 @@ class MediaStreamDispatcherTest : public ::testing::Test {
EXPECT_EQ(handler_->request_id_, request_id);
EXPECT_EQ(handler_->label_, label);
- if (audio_available)
+ if (options.audio_requested)
EXPECT_EQ(dispatcher_->audio_session_id(label, 0), kAudioSessionId);
- if (video_available)
+ if (options.video_requested)
EXPECT_EQ(dispatcher_->video_session_id(label, 0), kVideoSessionId);
return label;
@@ -184,7 +181,7 @@ class MediaStreamDispatcherTest : public ::testing::Test {
} // namespace
TEST_F(MediaStreamDispatcherTest, GenerateStreamAndStopDevices) {
- StreamOptions options(kAudioType, kVideoType);
+ StreamOptions options(true, true);
int ipc_request_id1 = GenerateStream(options, kRequestId1);
int ipc_request_id2 = GenerateStream(options, kRequestId2);
@@ -215,69 +212,6 @@ TEST_F(MediaStreamDispatcherTest, GenerateStreamAndStopDevices) {
StreamDeviceInfo::kNoId);
}
-TEST_F(MediaStreamDispatcherTest, BasicStreamForDevice) {
- static const char kDeviceId[] = "/dev/video0";
- scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
- scoped_ptr<MockMediaStreamDispatcherEventHandler>
- handler(new MockMediaStreamDispatcherEventHandler);
- StreamOptions components(kNoAudioType, kVideoType);
- components.audio_device_id = kDeviceId;
- components.video_device_id = kDeviceId;
- GURL security_origin;
-
- int ipc_request_id1 = dispatcher->next_ipc_id_;
- dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(),
- components, security_origin);
- int ipc_request_id2 = dispatcher->next_ipc_id_;
- EXPECT_NE(ipc_request_id1, ipc_request_id2);
- dispatcher->GenerateStream(kRequestId2, handler.get()->AsWeakPtr(),
- components, security_origin);
- EXPECT_EQ(dispatcher->requests_.size(), size_t(2));
-
- // No audio requested.
- StreamDeviceInfoArray audio_device_array;
-
- StreamDeviceInfoArray video_device_array(1);
- StreamDeviceInfo video_device_info;
- video_device_info.device.name = "Fake Video Capture Device";
- video_device_info.device.type = kVideoType;
- video_device_info.session_id = kVideoSessionId;
- video_device_array[0] = video_device_info;
-
- // Complete the creation of stream1.
- std::string stream_label1 = std::string("stream1");
- dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated(
- kRouteId, ipc_request_id1, stream_label1,
- audio_device_array, video_device_array));
- EXPECT_EQ(handler->request_id_, kRequestId1);
- EXPECT_EQ(handler->label_, stream_label1);
-
- // Complete the creation of stream2.
- std::string stream_label2 = std::string("stream2");
- dispatcher->OnMessageReceived(MediaStreamMsg_StreamGenerated(
- kRouteId, ipc_request_id2, stream_label2,
- audio_device_array, video_device_array));
- EXPECT_EQ(handler->request_id_, kRequestId2);
- EXPECT_EQ(handler->label_, stream_label2);
-
- EXPECT_EQ(dispatcher->requests_.size(), size_t(0));
- EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(2));
-
- // Check the session_id of stream2.
- EXPECT_EQ(dispatcher->video_session_id(stream_label2, 0), kVideoSessionId);
-
- // Stop video.
- dispatcher->StopStreamDevice(video_device_info);
- EXPECT_EQ(dispatcher->video_session_id(stream_label1, 0),
- StreamDeviceInfo::kNoId);
-
- EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0));
-
- // Verify that the request has been completed.
- EXPECT_EQ(dispatcher->label_stream_map_.size(), size_t(0));
- EXPECT_EQ(dispatcher->requests_.size(), size_t(0));
-}
-
TEST_F(MediaStreamDispatcherTest, BasicVideoDevice) {
scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
scoped_ptr<MockMediaStreamDispatcherEventHandler>
@@ -371,7 +305,7 @@ TEST_F(MediaStreamDispatcherTest, TestFailure) {
scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
scoped_ptr<MockMediaStreamDispatcherEventHandler>
handler(new MockMediaStreamDispatcherEventHandler);
- StreamOptions components(kAudioType, kVideoType);
+ StreamOptions components(true, true);
GURL security_origin;
// Test failure when creating a stream.
@@ -418,7 +352,7 @@ TEST_F(MediaStreamDispatcherTest, CancelGenerateStream) {
scoped_ptr<MediaStreamDispatcher> dispatcher(new MediaStreamDispatcher(NULL));
scoped_ptr<MockMediaStreamDispatcherEventHandler>
handler(new MockMediaStreamDispatcherEventHandler);
- StreamOptions components(kAudioType, kVideoType);
+ StreamOptions components(true, true);
int ipc_request_id1 = dispatcher->next_ipc_id_;
dispatcher->GenerateStream(kRequestId1, handler.get()->AsWeakPtr(),
@@ -457,7 +391,7 @@ TEST_F(MediaStreamDispatcherTest, CancelGenerateStream) {
// Test that the MediaStreamDispatcherEventHandler is notified when the message
// MediaStreamMsg_DeviceStopped is received.
TEST_F(MediaStreamDispatcherTest, DeviceClosed) {
- StreamOptions options(kAudioType, kVideoType);
+ StreamOptions options(true, true);
int ipc_request_id = GenerateStream(options, kRequestId1);
const std::string& label = CompleteGenerateStream(ipc_request_id, options,
diff --git a/content/renderer/media/media_stream_impl.cc b/content/renderer/media/media_stream_impl.cc
index a1dac1d..9266431d 100644
--- a/content/renderer/media/media_stream_impl.cc
+++ b/content/renderer/media/media_stream_impl.cc
@@ -33,55 +33,23 @@
namespace content {
namespace {
-std::string GetStreamConstraint(
- const blink::WebMediaConstraints& constraints, const std::string& key,
- bool is_mandatory) {
- if (constraints.isNull())
- return std::string();
-
- blink::WebString value;
- if (is_mandatory) {
- constraints.getMandatoryConstraintValue(UTF8ToUTF16(key), value);
- } else {
- constraints.getOptionalConstraintValue(UTF8ToUTF16(key), value);
- }
- return UTF16ToUTF8(value);
-}
-
-void UpdateRequestOptions(
- const blink::WebUserMediaRequest& user_media_request,
- StreamOptions* options) {
- if (options->audio_type != content::MEDIA_NO_SERVICE) {
- 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 = GetStreamConstraint(
- user_media_request.audioConstraints(),
- kMediaStreamSourceId, true);
- } else if (audio_stream_source == kMediaStreamSourceSystem) {
- options->audio_type = content::MEDIA_LOOPBACK_AUDIO_CAPTURE;
- }
+void CopyStreamConstraints(const blink::WebMediaConstraints& constraints,
+ StreamOptions::Constraints* mandatory,
+ StreamOptions::Constraints* optional) {
+ blink::WebVector<blink::WebMediaConstraint> mandatory_constraints;
+ constraints.getMandatoryConstraints(mandatory_constraints);
+ for (size_t i = 0; i < mandatory_constraints.size(); i++) {
+ mandatory->push_back(StreamOptions::Constraint(
+ mandatory_constraints[i].m_name.utf8(),
+ mandatory_constraints[i].m_value.utf8()));
}
- if (options->video_type != content::MEDIA_NO_SERVICE) {
- 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 = GetStreamConstraint(
- user_media_request.videoConstraints(),
- kMediaStreamSourceId, true);
- } else if (video_stream_source == kMediaStreamSourceScreen) {
- options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
- options->video_device_id =
- DesktopMediaID(DesktopMediaID::TYPE_SCREEN, 0).ToString();
- } else if (video_stream_source == kMediaStreamSourceDesktop) {
- options->video_type = content::MEDIA_DESKTOP_VIDEO_CAPTURE;
- options->video_device_id = GetStreamConstraint(
- user_media_request.videoConstraints(),
- kMediaStreamSourceId, true);
- }
+ blink::WebVector<blink::WebMediaConstraint> optional_constraints;
+ constraints.getOptionalConstraints(optional_constraints);
+ for (size_t i = 0; i < optional_constraints.size(); i++) {
+ optional->push_back(StreamOptions::Constraint(
+ optional_constraints[i].m_name.utf8(),
+ optional_constraints[i].m_value.utf8()));
}
}
@@ -139,7 +107,7 @@ void MediaStreamImpl::requestUserMedia(
UpdateWebRTCMethodCount(WEBKIT_GET_USER_MEDIA);
DCHECK(CalledOnValidThread());
int request_id = g_next_request_id++;
- StreamOptions options(MEDIA_NO_SERVICE, MEDIA_NO_SERVICE);
+ StreamOptions options;
blink::WebFrame* frame = NULL;
GURL security_origin;
bool enable_automatic_output_device_selection = false;
@@ -148,27 +116,29 @@ void MediaStreamImpl::requestUserMedia(
// if it isNull.
if (user_media_request.isNull()) {
// We are in a test.
- options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
- options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
+ options.audio_requested = true;
+ options.video_requested = true;
} else {
if (user_media_request.audio()) {
- options.audio_type = MEDIA_DEVICE_AUDIO_CAPTURE;
- options.audio_device_id = GetStreamConstraint(
- user_media_request.audioConstraints(),
- kMediaStreamSourceInfoId, false);
+ options.audio_requested = true;
+ CopyStreamConstraints(user_media_request.audioConstraints(),
+ &options.mandatory_audio,
+ &options.optional_audio);
+
// Check if this input device should be used to select a matching output
// device for audio rendering.
- std::string enable = GetStreamConstraint(
- user_media_request.audioConstraints(),
- kMediaStreamRenderToAssociatedSink, false);
- if (LowerCaseEqualsASCII(enable, "true"))
+ std::string enable;
+ if (options.GetFirstAudioConstraintByName(
+ kMediaStreamRenderToAssociatedSink, &enable, NULL) &&
+ LowerCaseEqualsASCII(enable, "true")) {
enable_automatic_output_device_selection = true;
+ }
}
if (user_media_request.video()) {
- options.video_type = MEDIA_DEVICE_VIDEO_CAPTURE;
- options.video_device_id = GetStreamConstraint(
- user_media_request.videoConstraints(),
- kMediaStreamSourceInfoId, false);
+ options.video_requested = true;
+ CopyStreamConstraints(user_media_request.videoConstraints(),
+ &options.mandatory_video,
+ &options.optional_video);
}
security_origin = GURL(user_media_request.securityOrigin().toString());
@@ -177,22 +147,33 @@ void MediaStreamImpl::requestUserMedia(
// out of scope.
frame = user_media_request.ownerDocument().frame();
DCHECK(frame);
-
- UpdateRequestOptions(user_media_request, &options);
}
DVLOG(1) << "MediaStreamImpl::requestUserMedia(" << request_id << ", [ "
- << "audio=" << (options.audio_type)
+ << "audio=" << (options.audio_requested)
<< " select associated sink: "
<< enable_automatic_output_device_selection
- << ", video=" << (options.video_type) << " ], "
+ << ", video=" << (options.video_requested) << " ], "
<< security_origin.spec() << ")";
+ std::string audio_device_id;
+ bool mandatory_audio;
+ options.GetFirstAudioConstraintByName(kMediaStreamSourceInfoId,
+ &audio_device_id, &mandatory_audio);
+ std::string video_device_id;
+ bool mandatory_video;
+ options.GetFirstVideoConstraintByName(kMediaStreamSourceInfoId,
+ &video_device_id, &mandatory_video);
+
WebRtcLogMessage(base::StringPrintf(
"MSI::requestUserMedia. request_id=%d"
- ", audio device id=%s",
+ ", audio source id=%s mandatory= %s "
+ ", video source id=%s mandatory= %s",
request_id,
- options.audio_device_id.c_str()));
+ audio_device_id.c_str(),
+ mandatory_audio ? "true":"false",
+ video_device_id.c_str(),
+ mandatory_video ? "true":"false"));
user_media_requests_.push_back(
new UserMediaRequestInfo(request_id, frame, user_media_request,
diff --git a/content/renderer/media/mock_media_stream_dispatcher.cc b/content/renderer/media/mock_media_stream_dispatcher.cc
index 793fe3a..ed5c91c 100644
--- a/content/renderer/media/mock_media_stream_dispatcher.cc
+++ b/content/renderer/media/mock_media_stream_dispatcher.cc
@@ -32,19 +32,19 @@ void MockMediaStreamDispatcher::GenerateStream(
audio_array_.clear();
video_array_.clear();
- if (IsAudioMediaType(components.audio_type)) {
+ if (components.audio_requested) {
StreamDeviceInfo audio;
audio.device.id = "audio_device_id" + base::IntToString(session_id_);
audio.device.name = "microphone";
- audio.device.type = components.audio_type;
+ audio.device.type = MEDIA_DEVICE_AUDIO_CAPTURE;
audio.session_id = session_id_;
audio_array_.push_back(audio);
}
- if (IsVideoMediaType(components.video_type)) {
+ if (components.video_requested) {
StreamDeviceInfo video;
video.device.id = "video_device_id" + base::IntToString(session_id_);
video.device.name = "usb video camera";
- video.device.type = components.video_type;
+ video.device.type = MEDIA_DEVICE_VIDEO_CAPTURE;
video.session_id = session_id_;
video_array_.push_back(video);
}
diff --git a/content/renderer/media/rtc_media_constraints.cc b/content/renderer/media/rtc_media_constraints.cc
index 235d9bd..4bdfd90 100644
--- a/content/renderer/media/rtc_media_constraints.cc
+++ b/content/renderer/media/rtc_media_constraints.cc
@@ -29,6 +29,10 @@ void GetNativeMediaConstraints(
new_constraint.key == kMediaStreamSourceId)
continue;
+ // Ignore sourceId constraint since that has nothing to do with webrtc.
+ if (new_constraint.key == kMediaStreamSourceInfoId)
+ continue;
+
// Ignore internal constraints set by JS.
if (StartsWithASCII(
new_constraint.key,