Bug 907352 - Part 1: Update to most recent constraints syntax. r=mt

This commit is contained in:
Jan-Ivar Bruaroey 2014-04-18 03:23:29 -04:00
parent 8360610c1d
commit 68500a88e9
14 changed files with 201 additions and 192 deletions

View File

@ -711,14 +711,12 @@ SpeechRecognition::Start(ErrorResult& aRv)
rv = mRecognitionService->Initialize(this->asWeakPtr());
NS_ENSURE_SUCCESS_VOID(rv);
AutoSafeJSContext cx;
MediaStreamConstraints constraints;
constraints.mAudio.SetAsBoolean() = true;
if (!mTestConfig.mFakeFSMEvents) {
MediaManager* manager = MediaManager::Get();
manager->GetUserMedia(cx,
false,
manager->GetUserMedia(false,
GetOwner(),
constraints,
new GetUserMediaSuccessCallback(this),

View File

@ -1294,8 +1294,7 @@ Navigator::SendBeacon(const nsAString& aUrl,
#ifdef MOZ_MEDIA_NAVIGATOR
void
Navigator::MozGetUserMedia(JSContext* aCx,
const MediaStreamConstraints& aConstraints,
Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
NavigatorUserMediaSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
ErrorResult& aRv)
@ -1318,12 +1317,12 @@ Navigator::MozGetUserMedia(JSContext* aCx,
bool privileged = nsContentUtils::IsChromeDoc(mWindow->GetExtantDoc());
MediaManager* manager = MediaManager::Get();
aRv = manager->GetUserMedia(aCx, privileged, mWindow, aConstraints,
aRv = manager->GetUserMedia(privileged, mWindow, aConstraints,
onsuccess, onerror);
}
void
Navigator::MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
Navigator::MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
uint64_t aInnerWindowID,

View File

@ -33,7 +33,6 @@ namespace dom {
class Geolocation;
class systemMessageCallback;
class MediaStreamConstraints;
class MediaStreamConstraintsInternal;
class WakeLock;
class ArrayBufferViewOrBlobOrStringOrFormData;
}
@ -231,12 +230,11 @@ public:
ErrorResult& aRv);
#ifdef MOZ_MEDIA_NAVIGATOR
void MozGetUserMedia(JSContext* aCx,
const MediaStreamConstraints& aConstraints,
void MozGetUserMedia(const MediaStreamConstraints& aConstraints,
NavigatorUserMediaSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
ErrorResult& aRv);
void MozGetUserMediaDevices(const MediaStreamConstraintsInternal& aConstraints,
void MozGetUserMediaDevices(const MediaStreamConstraints& aConstraints,
MozGetUserMediaDevicesSuccessCallback& aOnSuccess,
NavigatorUserMediaErrorCallback& aOnError,
uint64_t aInnerWindowID,

View File

@ -16,12 +16,12 @@ namespace dom {
GetUserMediaRequest::GetUserMediaRequest(
nsPIDOMWindow* aInnerWindow,
const nsAString& aCallID,
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
bool aIsSecure)
: mInnerWindowID(aInnerWindow->WindowID())
, mOuterWindowID(aInnerWindow->GetOuterWindow()->WindowID())
, mCallID(aCallID)
, mConstraints(new MediaStreamConstraintsInternal(aConstraints))
, mConstraints(new MediaStreamConstraints(aConstraints))
, mIsSecure(aIsSecure)
{
SetIsDOMBinding();
@ -67,7 +67,7 @@ bool GetUserMediaRequest::IsSecure()
}
void
GetUserMediaRequest::GetConstraints(MediaStreamConstraintsInternal &result)
GetUserMediaRequest::GetConstraints(MediaStreamConstraints &result)
{
result = *mConstraints;
}

View File

@ -14,14 +14,14 @@
namespace mozilla {
namespace dom {
class MediaStreamConstraintsInternal;
class MediaStreamConstraints;
class GetUserMediaRequest : public nsISupports, public nsWrapperCache
{
public:
GetUserMediaRequest(nsPIDOMWindow* aInnerWindow,
const nsAString& aCallID,
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
bool aIsSecure);
virtual ~GetUserMediaRequest() {};
@ -36,12 +36,12 @@ public:
uint64_t InnerWindowID();
bool IsSecure();
void GetCallID(nsString& retval);
void GetConstraints(MediaStreamConstraintsInternal &result);
void GetConstraints(MediaStreamConstraints &result);
private:
uint64_t mInnerWindowID, mOuterWindowID;
const nsString mCallID;
nsAutoPtr<MediaStreamConstraintsInternal> mConstraints;
nsAutoPtr<MediaStreamConstraints> mConstraints;
bool mIsSecure;
};

View File

@ -23,6 +23,7 @@
#include "nsIDocument.h"
#include "nsISupportsPrimitives.h"
#include "nsIInterfaceRequestorUtils.h"
#include "mozilla/Types.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/MediaStreamBinding.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
@ -74,53 +75,11 @@ GetMediaManagerLog()
#endif
using dom::MediaStreamConstraints; // Outside API (contains JSObject)
using dom::MediaStreamConstraintsInternal; // Storable supported constraints
using dom::MediaTrackConstraintsInternal; // Video or audio constraints
using dom::MediaTrackConstraintSet; // Mandatory or optional constraints
using dom::MediaTrackConstraints; // Raw mMandatory (as JSObject)
using dom::GetUserMediaRequest;
using dom::Sequence;
using dom::OwningBooleanOrMediaTrackConstraintsInternal;
// Used to compare raw MediaTrackConstraintSet against normalized dictionary
// version to detect member differences, e.g. unsupported constraints.
static nsresult CompareDictionaries(JSContext* aCx, JSObject *aA,
const MediaTrackConstraintSet &aB,
nsString *aDifference)
{
JS::Rooted<JSObject*> a(aCx, aA);
JSAutoCompartment ac(aCx, aA);
JS::Rooted<JS::Value> bval(aCx);
aB.ToObject(aCx, &bval);
JS::Rooted<JSObject*> b(aCx, &bval.toObject());
// Iterate over each property in A, and check if it is in B
JS::AutoIdArray props(aCx, JS_Enumerate(aCx, a));
for (size_t i = 0; i < props.length(); i++) {
JS::Rooted<JS::Value> bprop(aCx);
JS::Rooted<jsid> id(aCx, props[i]);
if (!JS_GetPropertyById(aCx, b, id, &bprop)) {
LOG(("Error parsing dictionary!\n"));
return NS_ERROR_UNEXPECTED;
}
if (bprop.isUndefined()) {
// Unknown property found in A. Bail with name
JS::Rooted<JS::Value> nameval(aCx);
bool success = JS_IdToValue(aCx, props[i], &nameval);
NS_ENSURE_TRUE(success, NS_ERROR_UNEXPECTED);
JS::Rooted<JSString*> namestr(aCx, JS::ToString(aCx, nameval));
NS_ENSURE_TRUE(namestr, NS_ERROR_UNEXPECTED);
aDifference->Assign(JS_GetStringCharsZ(aCx, namestr));
return NS_OK;
}
}
aDifference->Truncate();
return NS_OK;
}
using dom::OwningBooleanOrMediaTrackConstraints;
ErrorCallbackRunnable::ErrorCallbackRunnable(
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
@ -672,25 +631,34 @@ private:
};
static bool
IsOn(const dom::OwningBooleanOrMediaTrackConstraintsInternal &aUnion) {
IsOn(const dom::OwningBooleanOrMediaTrackConstraints &aUnion) {
return !aUnion.IsBoolean() || aUnion.GetAsBoolean();
}
static JSObject *
GetMandatoryJSObj(const dom::OwningBooleanOrMediaTrackConstraints &aUnion) {
return (aUnion.IsMediaTrackConstraints() &&
aUnion.GetAsMediaTrackConstraints().mMandatory.WasPassed()) ?
aUnion.GetAsMediaTrackConstraints().mMandatory.Value() : nullptr;
}
/**
* Helper functions that implement the constraints algorithm from
* http://dev.w3.org/2011/webrtc/editor/getusermedia.html#methods-5
*/
static bool SatisfyConstraint(const MediaEngineVideoSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
#define lengthof(a) (sizeof(a) / sizeof(*a))
static auto
GetSupportedConstraintNames(const MediaEngineVideoSource *) ->
decltype((dom::SupportedVideoConstraintsValues::strings)) {
return dom::SupportedVideoConstraintsValues::strings;
}
static auto
GetSupportedConstraintNames(const MediaEngineAudioSource *) ->
decltype((dom::SupportedAudioConstraintsValues::strings)) {
return dom::SupportedAudioConstraintsValues::strings;
}
// Reminder: add handling for new constraints both here and in GetSources below!
static bool SatisfyConstraintSet(const MediaEngineVideoSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
{
if (aConstraints.mFacingMode.WasPassed()) {
nsString s;
@ -704,14 +672,42 @@ static bool SatisfyConstraint(const MediaEngineVideoSource *,
return true;
}
static bool SatisfyConstraint(const MediaEngineAudioSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
static bool SatisfyConstraintSet(const MediaEngineAudioSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
{
// TODO: Add audio-specific constraints
return true;
}
// Triage constraints into required and nonrequired + detect missing requireds
class TriageHelper
{
public:
TriageHelper(const nsTArray<nsString>& aRequire)
: mRequire(aRequire)
, mNumRequirementsMet(0) {}
MediaTrackConstraintSet& Triage(const nsAString &name) {
if (mRequire.IndexOf(name) != mRequire.NoIndex) {
mNumRequirementsMet++;
return mRequired;
} else {
return mNonrequired;
}
}
bool RequirementsAreMet() {
MOZ_ASSERT(mNumRequirementsMet <= mRequire.Length());
return mNumRequirementsMet == mRequire.Length();
}
MediaTrackConstraintSet mRequired;
MediaTrackConstraintSet mNonrequired;
private:
const nsTArray<nsString> mRequire;
uint32_t mNumRequirementsMet;
};
typedef nsTArray<nsCOMPtr<nsIMediaDevice> > SourceSet;
// Source getter that constrains list returned
@ -719,7 +715,7 @@ typedef nsTArray<nsCOMPtr<nsIMediaDevice> > SourceSet;
template<class SourceType>
static SourceSet *
GetSources(MediaEngine *engine,
const OwningBooleanOrMediaTrackConstraintsInternal &aConstraints,
const OwningBooleanOrMediaTrackConstraints &aConstraints,
void (MediaEngine::* aEnumerate)(nsTArray<nsRefPtr<SourceType> >*),
char* media_device_name = nullptr)
{
@ -759,24 +755,69 @@ static SourceSet *
}
}
// If unconstrained then return the full list.
if (aConstraints.IsBoolean()) {
MOZ_ASSERT(aConstraints.GetAsBoolean());
result->MoveElementsFrom(candidateSet);
return result.forget();
}
auto& constraints = aConstraints.GetAsMediaTrackConstraintsInternal();
// Then apply mandatory constraints
// Otherwise apply constraints to the list of sources.
// Note: Iterator must be signed as it can dip below zero
for (int i = 0; i < int(candidateSet.Length()); i++) {
// Overloading instead of template specialization keeps things local
if (!SatisfyConstraint(type, constraints.mMandatory, *candidateSet[i])) {
candidateSet.RemoveElementAt(i--);
auto& constraints = aConstraints.GetAsMediaTrackConstraints();
const nsTArray<nsString> empty;
const auto &require = constraints.mRequire.WasPassed()?
constraints.mRequire.Value() : empty;
{
// Check upfront the names of required constraints that are unsupported for
// this media-type. The spec requires these to fail, so getting them out of
// the way early provides a necessary invariant for the remaining algorithm
// which maximizes code-reuse by ignoring constraints of the other type
// (specifically, SatisfyConstraintSet is reused for the advanced algorithm
// where the spec requires it to ignore constraints of the other type)
const auto& supported = GetSupportedConstraintNames(type);
for (uint32_t i = 0; i < require.Length(); i++) {
bool found = false;
// EnumType arrays have a zero-terminator entry at the end. Skip.
for (size_t j = 0; j < sizeof(supported)/sizeof(*supported) - 1; j++) {
if (require[i].EqualsASCII(supported[j].value)) {
found = true;
break;
}
}
if (!found) {
return result.forget();
}
}
}
// Then apply optional constraints.
// Before we start, triage constraints into required and nonrequired.
// Reminder: add handling for new constraints both here & SatisfyConstraintSet
TriageHelper helper(require);
if (constraints.mFacingMode.WasPassed()) {
helper.Triage(NS_LITERAL_STRING("facingMode")).mFacingMode.Construct(
constraints.mFacingMode.Value());
}
if (!helper.RequirementsAreMet()) {
return result.forget();
}
// Now on to the actual algorithm: First apply required constraints.
for (uint32_t i = 0; i < candidateSet.Length();) {
// Overloading instead of template specialization keeps things local
if (!SatisfyConstraintSet(type, helper.mRequired, *candidateSet[i])) {
candidateSet.RemoveElementAt(i);
} else {
++i;
}
}
// Then apply advanced (formerly known as optional) constraints.
//
// These are only effective when there are multiple sources to pick from.
// Spec as-of-this-writing says to run algorithm on "all possible tracks
@ -792,21 +833,26 @@ static SourceSet *
SourceSet tailSet;
if (constraints.mOptional.WasPassed()) {
const auto &array = constraints.mOptional.Value();
if (constraints.mAdvanced.WasPassed()) {
const auto &array = constraints.mAdvanced.Value();
for (int i = 0; i < int(array.Length()); i++) {
SourceSet rejects;
// Note: Iterator must be signed as it can dip below zero
for (int j = 0; j < int(candidateSet.Length()); j++) {
if (!SatisfyConstraint(type, array[i], *candidateSet[j])) {
for (uint32_t j = 0; j < candidateSet.Length();) {
if (!SatisfyConstraintSet(type, array[i], *candidateSet[j])) {
rejects.AppendElement(candidateSet[j]);
candidateSet.RemoveElementAt(j--);
candidateSet.RemoveElementAt(j);
} else {
++j;
}
}
(candidateSet.Length()? tailSet : candidateSet).MoveElementsFrom(rejects);
}
}
// Finally, order any remaining sources by how many nonrequired constraints
// they satisfy. TODO(jib): TBD once we implement >1 constraint (Bug 907352)
result->MoveElementsFrom(candidateSet);
result->MoveElementsFrom(tailSet);
return result.forget();
@ -825,7 +871,7 @@ class GetUserMediaRunnable : public nsRunnable
{
public:
GetUserMediaRunnable(
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
@ -846,7 +892,7 @@ public:
* using the one provided by MediaManager::GetBackend.
*/
GetUserMediaRunnable(
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
@ -952,7 +998,7 @@ public:
}
nsresult
SetContraints(const MediaStreamConstraintsInternal& aConstraints)
SetContraints(const MediaStreamConstraints& aConstraints)
{
mConstraints = aConstraints;
return NS_OK;
@ -1081,7 +1127,7 @@ public:
}
private:
MediaStreamConstraintsInternal mConstraints;
MediaStreamConstraints mConstraints;
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
@ -1107,7 +1153,7 @@ class GetUserMediaDevicesRunnable : public nsRunnable
{
public:
GetUserMediaDevicesRunnable(
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowId, char* aAudioLoopbackDev, char* aVideoLoopbackDev)
@ -1148,7 +1194,7 @@ public:
}
private:
MediaStreamConstraintsInternal mConstraints;
MediaStreamConstraints mConstraints;
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
nsRefPtr<MediaManager> mManager;
@ -1294,8 +1340,8 @@ MediaManager::NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
* for handling all incoming getUserMedia calls from every window.
*/
nsresult
MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
nsPIDOMWindow* aWindow, const MediaStreamConstraints& aRawConstraints,
MediaManager::GetUserMedia(bool aPrivileged,
nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError)
{
@ -1308,42 +1354,6 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
Maybe<JSAutoCompartment> ac;
JS::Rooted<JSObject*> audioObj (aCx, GetMandatoryJSObj(aRawConstraints.mAudio));
JS::Rooted<JSObject*> videoObj (aCx, GetMandatoryJSObj(aRawConstraints.mVideo));
if (audioObj || videoObj) {
ac.construct(aCx, audioObj? audioObj : videoObj);
}
// aRawConstraints may have JSObject in mMandatory, so copy everything into
// MediaStreamConstraintsInternal which does not.
dom::RootedDictionary<MediaStreamConstraintsInternal> c(aCx);
JS::Rooted<JS::Value> temp(aCx);
// This isn't the fastest way to copy a MediaStreamConstraints into a
// MediaStreamConstraintsInternal, but requires less code maintenance than an
// explicit member-by-member copy, and should be safe given the circumstances.
aRawConstraints.ToObject(aCx, &temp);
bool success = c.Init(aCx, temp);
NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);
// Validate mandatory constraints by detecting any unknown constraints.
// Done by comparing the raw MediaTrackConstraints against the normalized copy
nsString unknownConstraintFound;
if (audioObj) {
nsresult rv = CompareDictionaries(aCx, audioObj,
c.mAudio.GetAsMediaTrackConstraintsInternal().mMandatory,
&unknownConstraintFound);
NS_ENSURE_SUCCESS(rv, rv);
}
if (videoObj) {
nsresult rv = CompareDictionaries(aCx, videoObj,
c.mVideo.GetAsMediaTrackConstraintsInternal().mMandatory,
&unknownConstraintFound);
NS_ENSURE_SUCCESS(rv, rv);
}
/**
* If we were asked to get a picture, before getting a snapshot, we check if
* the calling page is allowed to open a popup. We do this because
@ -1394,23 +1404,6 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
GetActiveWindows()->Put(windowID, listeners);
}
if (!unknownConstraintFound.IsEmpty()) {
// An unsupported mandatory constraint was found.
//
// We continue to ignore these for now, because we implement just
// facingMode, which means all existing uses of mandatory width/height would
// fail on Firefox only otherwise, which is undesirable.
//
// There's also basis for always ignoring them in a new proposal.
// TODO(jib): This is a super-low-risk fix for backport. Clean up later.
LOG(("Unsupported mandatory constraint: %s\n",
NS_ConvertUTF16toUTF8(unknownConstraintFound).get()));
// unknown constraints existed in aRawConstraints only, which is unused
// from here, so continuing here effectively ignores them, as is desired.
}
// Ensure there's a thread for gum to proxy to off main thread
nsIThread *mediaThread = MediaManager::GetThread();
@ -1421,6 +1414,8 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
// No need for locking because we always do this in the main thread.
listeners->AppendElement(listener);
MediaStreamConstraints c(aConstraints); // copy
// Developer preference for turning off permission check.
if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
aPrivileged = true;
@ -1559,7 +1554,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
nsresult
MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
const MediaStreamConstraintsInternal& aConstraints,
const MediaStreamConstraints& aConstraints,
nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError,
uint64_t aInnerWindowID)

View File

@ -495,14 +495,14 @@ public:
void RemoveFromWindowList(uint64_t aWindowID,
GetUserMediaCallbackMediaStreamListener *aListener);
nsresult GetUserMedia(JSContext* aCx, bool aPrivileged,
nsresult GetUserMedia(bool aPrivileged,
nsPIDOMWindow* aWindow,
const dom::MediaStreamConstraints& aRawConstraints,
nsIDOMGetUserMediaSuccessCallback* onSuccess,
nsIDOMGetUserMediaErrorCallback* onError);
nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
const dom::MediaStreamConstraintsInternal& aConstraints,
const dom::MediaStreamConstraints& aConstraints,
nsIGetUserMediaDevicesSuccessCallback* onSuccess,
nsIDOMGetUserMediaErrorCallback* onError,
uint64_t aInnerWindowID = 0);

View File

@ -176,7 +176,7 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtr<dom::GetUserMediaRequest
nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
: mRequest(aRequest)
{
dom::MediaStreamConstraintsInternal constraints;
dom::MediaStreamConstraints constraints;
mRequest->GetConstraints(constraints);
mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean();
@ -578,7 +578,7 @@ MediaPermissionManager::HandleRequest(nsRefPtr<dom::GetUserMediaRequest> &req)
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError =
new MediaDeviceErrorCallback(callID);
dom::MediaStreamConstraintsInternal constraints;
dom::MediaStreamConstraints constraints;
req->GetConstraints(constraints);
nsRefPtr<MediaManager> MediaMgr = MediaManager::GetInstance();

View File

@ -20,24 +20,50 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=882145
<script type="application/javascript">
/**
Tests covering gUM constraints API for audio, video and fake video. Exercise
successful parsing code and ensure that unknown mandatory constraints and
successful parsing code and ensure that unknown required constraints and
overconstraining cases produce appropriate errors.
*/
var tests = [
// Each test here tests a different constraint or codepath.
{ message: "unknown required constraint on video fails",
constraints: { video: { somethingUnknown:0, require:["somethingUnknown"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "unknown required constraint on audio fails",
constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "missing required constraint on video fails",
constraints: { video: { require:["facingMode"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "missing required constraint on audio fails",
constraints: { audio: { require:["facingMode"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "video overconstrained by facingMode fails",
constraints: { video: { mandatory: { facingMode:'left' } } },
constraints: { video: { facingMode:'left', require:["facingMode"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "audio overconstrained by facingMode fails",
constraints: { audio: { facingMode:'left', require:["facingMode"] } },
error: "NO_DEVICES_FOUND",
pass: false },
{ message: "Success-path: optional video facingMode + audio ignoring facingMode",
constraints: { fake: true,
audio: { mandatory: { facingMode:'left' } },
video: { mandatory: { somethingUnknown:0 },
optional: [{ facingMode:'left' },
{ facingMode:'right' },
{ facingMode:'environment' },
audio: { facingMode:'left',
foo:0,
advanced: [{ facingMode:'environment' },
{ facingMode:'user' },
{ foo:0 }] } },
{ bar:0 }] },
video: { // TODO: Bug 767924 sequences in unions
//facingMode:['left', 'right', 'user', 'environment'],
//require:["facingMode"],
facingMode:'left',
foo:0,
advanced: [{ facingMode:'environment' },
{ facingMode:'user' },
{ bar:0 }] } },
error: null,
pass: false },
{ message: null },

View File

@ -49,7 +49,7 @@ var exceptionTests = [
message: "wrong object type as third parameter" },
// Each test here verifies constraint syntax as defined in webidl
{ params: [{ fake: true, video: { optional: [{ facingMode:'foo' }] } },
{ params: [{ fake: true, video: { advanced: [{ facingMode:'foo' }] } },
unexpectedCall, unexpectedCall],
error: "'facingMode' member of MediaTrackConstraintSet 'foo' is not a valid value for enumeration VideoFacingModeEnum.",
message: "invalid facingMode enum value" }

View File

@ -11,6 +11,6 @@ interface GetUserMediaRequest {
readonly attribute unsigned long long windowID;
readonly attribute unsigned long long innerWindowID;
readonly attribute DOMString callID;
MediaStreamConstraintsInternal getConstraints();
MediaStreamConstraints getConstraints();
readonly attribute boolean isSecure;
};

View File

@ -16,15 +16,8 @@
dictionary MediaStreamConstraints {
(boolean or MediaTrackConstraints) audio = false;
(boolean or MediaTrackConstraints) video = false;
boolean picture = false;
boolean fake = false;
};
dictionary MediaStreamConstraintsInternal {
(boolean or MediaTrackConstraintsInternal) audio;
(boolean or MediaTrackConstraintsInternal) video;
boolean picture = false;
boolean fake = false;
boolean picture = false; // Mozilla legacy
boolean fake = false; // for testing
};
interface MediaStream {

View File

@ -11,7 +11,7 @@
*/
// Important! Do not ever add members that might need tracing (e.g. object)
// to MediaTrackConstraintSet or any dictionary marked XxxInternal here
// to MediaTrackConstraintSet
enum VideoFacingModeEnum {
"user",
@ -20,26 +20,26 @@ enum VideoFacingModeEnum {
"right"
};
enum SupportedVideoConstraints {
"facingMode"
};
enum SupportedAudioConstraints {
"dummy"
};
dictionary MediaTrackConstraintSet {
VideoFacingModeEnum facingMode;
ConstrainVideoFacingMode facingMode;
};
// MediaTrackConstraint = single-property-subset of MediaTrackConstraintSet
// Implemented as full set. Test Object.keys(pair).length == 1
// typedef MediaTrackConstraintSet MediaTrackConstraint; // TODO: Bug 913053
dictionary MediaTrackConstraints {
object mandatory; // so we can see unknown + unsupported constraints
sequence<MediaTrackConstraintSet> _optional; // a.k.a. MediaTrackConstraint
dictionary MediaTrackConstraints : MediaTrackConstraintSet {
sequence<DOMString> require;
sequence<MediaTrackConstraintSet> advanced;
};
// Internal dictionary holds result of processing raw MediaTrackConstraints above
dictionary MediaTrackConstraintsInternal {
MediaTrackConstraintSet mandatory; // holds only supported constraints
sequence<MediaTrackConstraintSet> _optional; // a.k.a. MediaTrackConstraint
};
typedef VideoFacingModeEnum ConstrainVideoFacingMode;
// TODO: Bug 767924 sequences in unions
//typedef (VideoFacingModeEnum or sequence<VideoFacingModeEnum>) ConstrainVideoFacingMode;
interface MediaStreamTrack {
readonly attribute DOMString kind;

View File

@ -337,7 +337,7 @@ partial interface Navigator {
callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
partial interface Navigator {
[Throws, ChromeOnly]
void mozGetUserMediaDevices(MediaStreamConstraintsInternal constraints,
void mozGetUserMediaDevices(MediaStreamConstraints constraints,
MozGetUserMediaDevicesSuccessCallback onsuccess,
NavigatorUserMediaErrorCallback onerror,
// The originating innerWindowID is needed to