Commit 33fb88b2 authored by hta@chromium.org's avatar hta@chromium.org

Implement navigator.mediaDevices.getUserMedia()

This makes a promise-based API for acquiring media available.

The implementation is still hidden behind the flag that guards MediaDevices (EnumerateDevices), so is not immediately available to users.

R=tommi
BUG=503227

Review URL: https://codereview.chromium.org/1202553002

git-svn-id: svn://svn.chromium.org/blink/trunk@197920 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent ddd1c61a
<!DOCTYPE HTML>
<html>
<head>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
</head>
<body>
<script>
promise_test(function() {
assert_idl_attribute(navigator, 'mediaDevices');
assert_idl_attribute(navigator.mediaDevices, 'getUserMedia');
return navigator.mediaDevices.getUserMedia({audio: true}).then(function(s) {
assert_equals(s.getTracks().length, 1);
});
}, 'getUserMedia() audio track');
promise_test(function() {
assert_idl_attribute(navigator, 'mediaDevices');
assert_idl_attribute(navigator.mediaDevices, 'getUserMedia');
return navigator.mediaDevices.getUserMedia({audio: true, video:true})
.then(function(s) {
assert_equals(s.getTracks().length, 2);
assert_equals(s.getAudioTracks().length, 1);
assert_equals(s.getVideoTracks().length, 1);
});
}, 'getUserMedia() audio and video tracks');
promise_test(function() {
return navigator.mediaDevices.getUserMedia(
{audio: {'mandatory': { 'valid_but_unsupported_1': 0}}})
.then(function(s) {
fail('getUserMedia should have failed');
}).catch(function(e) {
assert_equals(e.name, 'ConstraintNotSatisfiedError');
});
}, 'getUserMedia() with unsupported mandatory constraint');
</script>
</body>
</html>
......@@ -11,6 +11,10 @@
#include "core/dom/DOMException.h"
#include "core/dom/Document.h"
#include "core/dom/ExceptionCode.h"
#include "modules/mediastream/MediaStream.h"
#include "modules/mediastream/NavigatorMediaStream.h"
#include "modules/mediastream/NavigatorUserMediaErrorCallback.h"
#include "modules/mediastream/NavigatorUserMediaSuccessCallback.h"
#include "modules/mediastream/UserMediaController.h"
namespace blink {
......@@ -26,4 +30,68 @@ ScriptPromise MediaDevices::enumerateDevices(ScriptState* scriptState)
return request->start();
}
namespace {
class PromiseSuccessCallback : public NavigatorUserMediaSuccessCallback {
public:
PromiseSuccessCallback(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
: m_resolver(resolver)
{
}
~PromiseSuccessCallback()
{
}
void handleEvent(MediaStream* stream)
{
m_resolver->resolve(stream);
}
private:
RefPtrWillBeRawPtr<ScriptPromiseResolver> m_resolver;
};
class PromiseErrorCallback : public NavigatorUserMediaErrorCallback {
public:
PromiseErrorCallback(PassRefPtrWillBeRawPtr<ScriptPromiseResolver> resolver)
: m_resolver(resolver)
{
}
~PromiseErrorCallback()
{
}
void handleEvent(NavigatorUserMediaError* error)
{
m_resolver->reject(error);
}
private:
RefPtrWillBeRawPtr<ScriptPromiseResolver> m_resolver;
};
} // namespace
ScriptPromise MediaDevices::getUserMedia(ScriptState* scriptState, const Dictionary& options, ExceptionState& exceptionState)
{
RefPtrWillBeRawPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
NavigatorUserMediaSuccessCallback* successCallback = new PromiseSuccessCallback(resolver);
NavigatorUserMediaErrorCallback* errorCallback = new PromiseErrorCallback(resolver);
Document* document = toDocument(scriptState->executionContext());
UserMediaController* userMedia = UserMediaController::from(document->frame());
if (!userMedia)
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError, "No media device controller available; is this a detached window?"));
UserMediaRequest* request = UserMediaRequest::create(document, userMedia, options, successCallback, errorCallback, exceptionState);
if (!request) {
ASSERT(exceptionState.hadException());
return exceptionState.reject(scriptState);
}
request->start();
return resolver->promise();
}
} // namespace blink
......@@ -10,6 +10,7 @@
namespace blink {
class Dictionary;
class ScriptState;
class MediaDevices final : public GarbageCollected<MediaDevices>, public ScriptWrappable {
......@@ -21,7 +22,7 @@ public:
}
ScriptPromise enumerateDevices(ScriptState*);
ScriptPromise getUserMedia(ScriptState*, const Dictionary&, ExceptionState&);
DEFINE_INLINE_TRACE() { }
private:
......
......@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The spec for MediaDevices is in two parts:
// http://w3c.github.io/mediacapture-main/#mediadevices
// http://w3c.github.io/mediacapture-main/#mediadevices-interface-extensions
[
GarbageCollected,
......@@ -10,4 +12,5 @@
]
interface MediaDevices {
[RuntimeEnabled=EnumerateDevices, TypeChecking=Interface, CallWith=ScriptState] Promise<sequence<MediaDeviceInfo>> enumerateDevices();
[CallWith=ScriptState, RaisesException] Promise<MediaStream> getUserMedia(Dictionary options);
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment