Backed out changesets d8d01c95be03 and 5fa0c8f5ccb2 (bug 907352) for Linux64 mochitest-3 crashes.

This commit is contained in:
Ryan VanderMeulen 2014-04-18 11:22:21 -04:00
parent e12bca044a
commit d503f72d54
17 changed files with 239 additions and 327 deletions

View File

@ -711,12 +711,14 @@ 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(false,
manager->GetUserMedia(cx,
false,
GetOwner(),
constraints,
new GetUserMediaSuccessCallback(this),

View File

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

View File

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

View File

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

View File

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

View File

@ -23,7 +23,6 @@
#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"
@ -75,11 +74,53 @@ 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::OwningBooleanOrMediaTrackConstraints;
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;
}
ErrorCallbackRunnable::ErrorCallbackRunnable(
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
@ -631,34 +672,25 @@ private:
};
static bool
IsOn(const dom::OwningBooleanOrMediaTrackConstraints &aUnion) {
IsOn(const dom::OwningBooleanOrMediaTrackConstraintsInternal &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
*/
#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)
static bool SatisfyConstraint(const MediaEngineVideoSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
{
if (aConstraints.mFacingMode.WasPassed()) {
nsString s;
@ -672,42 +704,14 @@ static bool SatisfyConstraintSet(const MediaEngineVideoSource *,
return true;
}
static bool SatisfyConstraintSet(const MediaEngineAudioSource *,
const MediaTrackConstraintSet &aConstraints,
nsIMediaDevice &aCandidate)
static bool SatisfyConstraint(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
@ -715,7 +719,7 @@ typedef nsTArray<nsCOMPtr<nsIMediaDevice> > SourceSet;
template<class SourceType>
static SourceSet *
GetSources(MediaEngine *engine,
const OwningBooleanOrMediaTrackConstraints &aConstraints,
const OwningBooleanOrMediaTrackConstraintsInternal &aConstraints,
void (MediaEngine::* aEnumerate)(nsTArray<nsRefPtr<SourceType> >*),
char* media_device_name = nullptr)
{
@ -755,69 +759,24 @@ 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();
// Otherwise apply constraints to the list of sources.
// Then apply mandatory constraints
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();
}
}
}
// 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();) {
// 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 (!SatisfyConstraintSet(type, helper.mRequired, *candidateSet[i])) {
candidateSet.RemoveElementAt(i);
} else {
++i;
if (!SatisfyConstraint(type, constraints.mMandatory, *candidateSet[i])) {
candidateSet.RemoveElementAt(i--);
}
}
// Then apply advanced (formerly known as optional) constraints.
// Then apply 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
@ -833,26 +792,21 @@ static SourceSet *
SourceSet tailSet;
if (constraints.mAdvanced.WasPassed()) {
const auto &array = constraints.mAdvanced.Value();
if (constraints.mOptional.WasPassed()) {
const auto &array = constraints.mOptional.Value();
for (int i = 0; i < int(array.Length()); i++) {
SourceSet rejects;
for (uint32_t j = 0; j < candidateSet.Length();) {
if (!SatisfyConstraintSet(type, array[i], *candidateSet[j])) {
// 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])) {
rejects.AppendElement(candidateSet[j]);
candidateSet.RemoveElementAt(j);
} else {
++j;
candidateSet.RemoveElementAt(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();
@ -871,7 +825,7 @@ class GetUserMediaRunnable : public nsRunnable
{
public:
GetUserMediaRunnable(
const MediaStreamConstraints& aConstraints,
const MediaStreamConstraintsInternal& aConstraints,
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
@ -892,7 +846,7 @@ public:
* using the one provided by MediaManager::GetBackend.
*/
GetUserMediaRunnable(
const MediaStreamConstraints& aConstraints,
const MediaStreamConstraintsInternal& aConstraints,
already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
@ -998,7 +952,7 @@ public:
}
nsresult
SetContraints(const MediaStreamConstraints& aConstraints)
SetContraints(const MediaStreamConstraintsInternal& aConstraints)
{
mConstraints = aConstraints;
return NS_OK;
@ -1127,7 +1081,7 @@ public:
}
private:
MediaStreamConstraints mConstraints;
MediaStreamConstraintsInternal mConstraints;
nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
@ -1153,7 +1107,7 @@ class GetUserMediaDevicesRunnable : public nsRunnable
{
public:
GetUserMediaDevicesRunnable(
const MediaStreamConstraints& aConstraints,
const MediaStreamConstraintsInternal& aConstraints,
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
uint64_t aWindowId, char* aAudioLoopbackDev, char* aVideoLoopbackDev)
@ -1194,7 +1148,7 @@ public:
}
private:
MediaStreamConstraints mConstraints;
MediaStreamConstraintsInternal mConstraints;
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
nsRefPtr<MediaManager> mManager;
@ -1340,8 +1294,8 @@ MediaManager::NotifyRecordingStatusChange(nsPIDOMWindow* aWindow,
* for handling all incoming getUserMedia calls from every window.
*/
nsresult
MediaManager::GetUserMedia(bool aPrivileged,
nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged,
nsPIDOMWindow* aWindow, const MediaStreamConstraints& aRawConstraints,
nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError)
{
@ -1354,6 +1308,42 @@ MediaManager::GetUserMedia(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
@ -1404,6 +1394,23 @@ MediaManager::GetUserMedia(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();
@ -1414,8 +1421,6 @@ MediaManager::GetUserMedia(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;
@ -1424,30 +1429,6 @@ MediaManager::GetUserMedia(bool aPrivileged,
c.mVideo.SetAsBoolean() = false;
}
#if defined(ANDROID) || defined(MOZ_WIDGET_GONK)
// Be backwards compatible only on mobile and only for facingMode.
if (c.mVideo.IsMediaTrackConstraints()) {
auto& tc = c.mVideo.GetAsMediaTrackConstraints();
if (!tc.mRequire.WasPassed()) {
if (tc.mMandatory.mFacingMode.WasPassed() && !tc.mFacingMode.WasPassed()) {
tc.mFacingMode.Construct(tc.mMandatory.mFacingMode.Value());
tc.mRequire.Construct().AppendElement(NS_LITERAL_STRING("facingMode"));
}
}
if (tc.mOptional.WasPassed() && !tc.mAdvanced.WasPassed()) {
tc.mAdvanced.Construct();
for (uint32_t i = 0; i < tc.mOptional.Value().Length(); i++) {
if (tc.mOptional.Value()[i].mFacingMode.WasPassed()) {
MediaTrackConstraintSet n;
n.mFacingMode.Construct(tc.mOptional.Value()[i].mFacingMode.Value());
tc.mAdvanced.Value().AppendElement(n);
}
}
}
}
#endif
// Pass callbacks and MediaStreamListener along to GetUserMediaRunnable.
nsRefPtr<GetUserMediaRunnable> runnable;
if (c.mFake) {
@ -1578,7 +1559,7 @@ MediaManager::GetUserMedia(bool aPrivileged,
nsresult
MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
const MediaStreamConstraints& aConstraints,
const MediaStreamConstraintsInternal& aConstraints,
nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
nsIDOMGetUserMediaErrorCallback* aOnError,
uint64_t aInnerWindowID)

View File

@ -495,14 +495,14 @@ public:
void RemoveFromWindowList(uint64_t aWindowID,
GetUserMediaCallbackMediaStreamListener *aListener);
nsresult GetUserMedia(bool aPrivileged,
nsresult GetUserMedia(JSContext* aCx, bool aPrivileged,
nsPIDOMWindow* aWindow,
const dom::MediaStreamConstraints& aRawConstraints,
nsIDOMGetUserMediaSuccessCallback* onSuccess,
nsIDOMGetUserMediaErrorCallback* onError);
nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
const dom::MediaStreamConstraints& aConstraints,
const dom::MediaStreamConstraintsInternal& 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::MediaStreamConstraints constraints;
dom::MediaStreamConstraintsInternal 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::MediaStreamConstraints constraints;
dom::MediaStreamConstraintsInternal constraints;
req->GetConstraints(constraints);
nsRefPtr<MediaManager> MediaMgr = MediaManager::GetInstance();

View File

@ -1,78 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
Tests covering gUM constraints API for audio, video and fake video. Exercise
successful parsing code and ensure that unknown required constraints and
overconstraining cases produce appropriate errors.
TODO(jib): Merge desktop and mobile version of these tests again.
*/
var common_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" },
{ message: "unknown required constraint on audio fails",
constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] } },
error: "NO_DEVICES_FOUND" },
{ message: "missing required constraint on video fails",
constraints: { video: { require:["facingMode"] } },
error: "NO_DEVICES_FOUND" },
{ message: "missing required constraint on audio fails",
constraints: { audio: { require:["facingMode"] } },
error: "NO_DEVICES_FOUND" },
{ message: "video overconstrained by facingMode fails",
constraints: { video: { facingMode:'left', require:["facingMode"] } },
error: "NO_DEVICES_FOUND" },
{ message: "audio overconstrained by facingMode fails",
constraints: { audio: { facingMode:'left', require:["facingMode"] } },
error: "NO_DEVICES_FOUND" },
{ message: "Success-path: optional video facingMode + audio ignoring facingMode",
constraints: { fake: true,
audio: { facingMode:'left',
foo:0,
advanced: [{ facingMode:'environment' },
{ facingMode:'user' },
{ 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 }
];
/**
* Starts the test run by running through each constraint
* test by verifying that the right callback and error message is fired.
*/
function testConstraints(tests) {
var i = 0;
next();
function Success() {
ok(!tests[i].error, tests[i].message);
i++;
next();
}
function Failure(err) {
ok(tests[i].error? (err === tests[i].error) : false,
tests[i].message + " (err=" + err + ")");
i++;
next();
}
function next() {
if (i < tests.length) {
navigator.mozGetUserMedia(tests[i].constraints, Success, Failure);
} else {
SimpleTest.finish();
}
}
};

View File

@ -1,7 +1,6 @@
[DEFAULT]
support-files =
head.js
constraints.js
mediaStreamPlayback.js
pc.js
templates.js
@ -26,9 +25,6 @@ skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_getUserMedia_basicVideoAudio.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure, turned an intermittent (bug 962579) into a permanant orange
[test_getUserMedia_constraints.html]
skip-if = (toolkit=='gonk' || toolkit=='android') # Bug 907352, backwards-compatible behavior on mobile only
[test_getUserMedia_constraints_mobile.html]
skip-if = (toolkit!='gonk' && toolkit!='android') # Bug 907352, backwards-compatible behavior on mobile only
[test_getUserMedia_exceptions.html]
[test_getUserMedia_gumWithinGum.html]
[test_getUserMedia_playAudioTwice.html]

View File

@ -9,10 +9,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=882145
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="constraints.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=882145">Test mozGetUserMedia Constraints (desktop)</a>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=882145">Test mozGetUserMedia Constraints</a>
<p id="display"></p>
<div id="content" style="display: none">
@ -20,17 +19,67 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=882145
<pre id="test">
<script type="application/javascript">
/**
See constraints.js for testConstraints() and common_tests.
TODO(jib): Merge desktop and mobile version of these tests again (Bug 997365)
Tests covering gUM constraints API for audio, video and fake video. Exercise
successful parsing code and ensure that unknown mandatory constraints and
overconstraining cases produce appropriate errors.
*/
var desktop_tests = [
{ message: "legacy facingMode ignored (desktop)",
constraints: { fake: true, video: { mandatory: { facingMode:'left' } } },
error: null },
var tests = [
// Each test here tests a different constraint or codepath.
{ message: "video overconstrained by facingMode fails",
constraints: { video: { mandatory: { facingMode:'left' } } },
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' },
{ facingMode:'user' },
{ foo:0 }] } },
error: null,
pass: false },
{ message: null },
];
/**
* Starts the test run by running through each constraint
* test by verifying that the right callback and error message is fired.
*/
runTest(function () {
testConstraints(common_tests.concat(desktop_tests));
var i = 0;
next();
function Success() {
info("successcallback");
tests[i].pass = !tests[i].error;
i++;
next();
}
function Failure(err) {
info("errcallback: " + err);
tests[i].pass = tests[i].error? (err === tests[i].error) : false;
i++;
next();
}
function next() {
if (tests[i].message) {
navigator.mozGetUserMedia(tests[i].constraints, Success, Failure);
} else {
finish();
}
}
function finish() {
tests.forEach(function (test) {
if (test.message) {
ok(test.pass, test.message);
} else {
SimpleTest.finish();
}
});
}
});

View File

@ -1,40 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=882145
-->
<head>
<meta charset="utf-8">
<title>Test mozGetUserMedia Constraints</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="constraints.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=882145">Test mozGetUserMedia Constraints (mobile)</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/**
See constraints.js for testConstraints() and common_tests.
TODO(jib): Merge desktop and mobile version of these tests again (Bug 997365)
*/
var mobile_tests = [
{ message: "legacy facingMode overconstrains video (mobile)",
constraints: { video: { mandatory: { facingMode:'left' } } },
error: "NO_DEVICES_FOUND" },
];
runTest(function () {
testConstraints(common_tests.concat(mobile_tests));
});
</script>
</pre>
</body>
</html>

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: { advanced: [{ facingMode:'foo' }] } },
{ params: [{ fake: true, video: { optional: [{ 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;
MediaStreamConstraints getConstraints();
MediaStreamConstraintsInternal getConstraints();
readonly attribute boolean isSecure;
};

View File

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

View File

@ -11,7 +11,7 @@
*/
// Important! Do not ever add members that might need tracing (e.g. object)
// to MediaTrackConstraintSet
// to MediaTrackConstraintSet or any dictionary marked XxxInternal here
enum VideoFacingModeEnum {
"user",
@ -20,34 +20,26 @@ enum VideoFacingModeEnum {
"right"
};
enum SupportedVideoConstraints {
"facingMode"
};
enum SupportedAudioConstraints {
"dummy"
};
dictionary MediaTrackConstraintSet {
ConstrainVideoFacingMode facingMode;
};
dictionary MobileLegacyMediaTrackConstraintSet {
VideoFacingModeEnum facingMode;
};
dictionary MediaTrackConstraints : MediaTrackConstraintSet {
sequence<DOMString> require;
sequence<MediaTrackConstraintSet> advanced;
// MediaTrackConstraint = single-property-subset of MediaTrackConstraintSet
// Implemented as full set. Test Object.keys(pair).length == 1
// mobile-only backwards-compatibility for facingMode
MobileLegacyMediaTrackConstraintSet mandatory;
sequence<MobileLegacyMediaTrackConstraintSet> _optional;
// typedef MediaTrackConstraintSet MediaTrackConstraint; // TODO: Bug 913053
dictionary MediaTrackConstraints {
object mandatory; // so we can see unknown + unsupported constraints
sequence<MediaTrackConstraintSet> _optional; // a.k.a. MediaTrackConstraint
};
typedef VideoFacingModeEnum ConstrainVideoFacingMode;
// TODO: Bug 767924 sequences in unions
//typedef (VideoFacingModeEnum or sequence<VideoFacingModeEnum>) ConstrainVideoFacingMode;
// Internal dictionary holds result of processing raw MediaTrackConstraints above
dictionary MediaTrackConstraintsInternal {
MediaTrackConstraintSet mandatory; // holds only supported constraints
sequence<MediaTrackConstraintSet> _optional; // a.k.a. MediaTrackConstraint
};
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(MediaStreamConstraints constraints,
void mozGetUserMediaDevices(MediaStreamConstraintsInternal constraints,
MozGetUserMediaDevicesSuccessCallback onsuccess,
NavigatorUserMediaErrorCallback onerror,
// The originating innerWindowID is needed to