diff --git a/CLOBBER b/CLOBBER index d050fcc09dea..4108b26533d8 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 991256 requires a clobber because it renames generated mobile/android/base/widget files. +Bug 916012 moves definition from one WEBIDL_FILE to another (Bug 979886) diff --git a/dom/media/GetUserMediaRequest.cpp b/dom/media/GetUserMediaRequest.cpp index cb39a284e6bc..23f2359e2457 100644 --- a/dom/media/GetUserMediaRequest.cpp +++ b/dom/media/GetUserMediaRequest.cpp @@ -4,7 +4,7 @@ #include "base/basictypes.h" #include "GetUserMediaRequest.h" -#include "mozilla/dom/MediaStreamTrackBinding.h" +#include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/GetUserMediaRequestBinding.h" #include "nsIScriptGlobalObject.h" #include "nsPIDOMWindow.h" @@ -20,7 +20,7 @@ GetUserMediaRequest::GetUserMediaRequest( : mInnerWindowID(aInnerWindow->WindowID()) , mOuterWindowID(aInnerWindow->GetOuterWindow()->WindowID()) , mCallID(aCallID) - , mConstraints(aConstraints) + , mConstraints(new MediaStreamConstraintsInternal(aConstraints)) { SetIsDOMBinding(); } @@ -62,7 +62,7 @@ uint64_t GetUserMediaRequest::InnerWindowID() void GetUserMediaRequest::GetConstraints(MediaStreamConstraintsInternal &result) { - result = mConstraints; + result = *mConstraints; } } // namespace dom diff --git a/dom/media/GetUserMediaRequest.h b/dom/media/GetUserMediaRequest.h index 38d2c85918b5..be411b5cb790 100644 --- a/dom/media/GetUserMediaRequest.h +++ b/dom/media/GetUserMediaRequest.h @@ -10,7 +10,6 @@ #include "nsAutoPtr.h" #include "nsWrapperCache.h" #include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/MediaStreamTrackBinding.h" #include "nsPIDOMWindow.h" namespace mozilla { @@ -40,7 +39,7 @@ public: private: uint64_t mInnerWindowID, mOuterWindowID; const nsString mCallID; - MediaStreamConstraintsInternal mConstraints; + nsAutoPtr mConstraints; }; } // namespace dom diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 287dfc005758..aac8bc6fb855 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -24,6 +24,7 @@ #include "nsISupportsPrimitives.h" #include "nsIInterfaceRequestorUtils.h" #include "mozilla/dom/ContentChild.h" +#include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/MediaStreamTrackBinding.h" #include "mozilla/dom/GetUserMediaRequestBinding.h" @@ -79,6 +80,7 @@ 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. @@ -120,29 +122,6 @@ static nsresult CompareDictionaries(JSContext* aCx, JSObject *aA, return NS_OK; } -// Look for and return any unknown mandatory constraint. Done by comparing -// a raw MediaTrackConstraints against a normalized copy, both passed in. - -static nsresult ValidateTrackConstraints( - JSContext *aCx, JSObject *aRaw, - const MediaTrackConstraintsInternal &aNormalized, - nsString *aOutUnknownConstraint) -{ - // First find raw mMandatory member (use MediaTrackConstraints as helper) - JS::Rooted rawval(aCx, JS::ObjectValue(*aRaw)); - dom::RootedDictionary track(aCx); - bool success = track.Init(aCx, rawval); - NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); - - if (track.mMandatory.WasPassed()) { - nsresult rv = CompareDictionaries(aCx, track.mMandatory.Value(), - aNormalized.mMandatory, - aOutUnknownConstraint); - NS_ENSURE_SUCCESS(rv, rv); - } - return NS_OK; -} - ErrorCallbackRunnable::ErrorCallbackRunnable( nsCOMPtr& aSuccess, nsCOMPtr& aError, @@ -692,6 +671,18 @@ private: nsRefPtr mManager; // get ref to this when creating the runnable }; +static bool +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 @@ -728,10 +719,16 @@ typedef nsTArray > SourceSet; template static SourceSet * GetSources(MediaEngine *engine, - const MediaTrackConstraintsInternal &aConstraints, + const OwningBooleanOrMediaTrackConstraintsInternal &aConstraints, void (MediaEngine::* aEnumerate)(nsTArray >*), char* media_device_name = nullptr) { + ScopedDeletePtr result(new SourceSet); + + if (!IsOn(aConstraints)) { + return result.forget(); + } + const SourceType * const type = nullptr; nsString deviceName; // First collect sources @@ -762,12 +759,19 @@ static SourceSet * } } + if (aConstraints.IsBoolean()) { + MOZ_ASSERT(aConstraints.GetAsBoolean()); + result->MoveElementsFrom(candidateSet); + return result.forget(); + } + auto& constraints = aConstraints.GetAsMediaTrackConstraintsInternal(); + // Then apply mandatory constraints // 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, aConstraints.mMandatory, *candidateSet[i])) { + if (!SatisfyConstraint(type, constraints.mMandatory, *candidateSet[i])) { candidateSet.RemoveElementAt(i--); } } @@ -788,8 +792,8 @@ static SourceSet * SourceSet tailSet; - if (aConstraints.mOptional.WasPassed()) { - const Sequence &array = aConstraints.mOptional.Value(); + if (constraints.mOptional.WasPassed()) { + const auto &array = constraints.mOptional.Value(); for (int i = 0; i < int(array.Length()); i++) { SourceSet rejects; // Note: Iterator must be signed as it can dip below zero @@ -803,10 +807,9 @@ static SourceSet * } } - SourceSet *result = new SourceSet; result->MoveElementsFrom(candidateSet); result->MoveElementsFrom(tailSet); - return result; + return result.forget(); } /** @@ -896,7 +899,8 @@ public: } // It is an error if audio or video are requested along with picture. - if (mConstraints.mPicture && (mConstraints.mAudio || mConstraints.mVideo)) { + if (mConstraints.mPicture && + (IsOn(mConstraints.mAudio) || IsOn(mConstraints.mVideo))) { Fail(NS_LITERAL_STRING("NOT_SUPPORTED_ERR")); return NS_OK; } @@ -907,9 +911,9 @@ public: } // There's a bug in the permission code that can leave us with mAudio but no audio device - ProcessGetUserMedia(((mConstraints.mAudio && mAudioDevice) ? + ProcessGetUserMedia(((IsOn(mConstraints.mAudio) && mAudioDevice) ? mAudioDevice->GetSource() : nullptr), - ((mConstraints.mVideo && mVideoDevice) ? + ((IsOn(mConstraints.mVideo) && mVideoDevice) ? mVideoDevice->GetSource() : nullptr)); return NS_OK; } @@ -975,9 +979,9 @@ public: { MOZ_ASSERT(mSuccess); MOZ_ASSERT(mError); - if (mConstraints.mPicture || mConstraints.mVideo) { + if (mConstraints.mPicture || IsOn(mConstraints.mVideo)) { ScopedDeletePtr sources (GetSources(backend, - mConstraints.mVideom, &MediaEngine::EnumerateVideoDevices)); + mConstraints.mVideo, &MediaEngine::EnumerateVideoDevices)); if (!sources->Length()) { Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND")); @@ -988,9 +992,9 @@ public: LOG(("Selected video device")); } - if (mConstraints.mAudio) { + if (IsOn(mConstraints.mAudio)) { ScopedDeletePtr sources (GetSources(backend, - mConstraints.mAudiom, &MediaEngine::EnumerateAudioDevices)); + mConstraints.mAudio, &MediaEngine::EnumerateAudioDevices)); if (!sources->Length()) { Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND")); @@ -1126,11 +1130,11 @@ public: else backend = mManager->GetBackend(mWindowId); - ScopedDeletePtr final (GetSources(backend, mConstraints.mVideom, + ScopedDeletePtr final (GetSources(backend, mConstraints.mVideo, &MediaEngine::EnumerateVideoDevices, mLoopbackVideoDevice)); { - ScopedDeletePtr s (GetSources(backend, mConstraints.mAudiom, + ScopedDeletePtr s (GetSources(backend, mConstraints.mAudio, &MediaEngine::EnumerateAudioDevices, mLoopbackAudioDevice)); final->MoveElementsFrom(*s); @@ -1305,52 +1309,40 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, nsCOMPtr onError(aOnError); Maybe ac; - if (aRawConstraints.mAudio.IsObject() || aRawConstraints.mVideo.IsObject()) { - ac.construct(aCx, (aRawConstraints.mVideo.IsObject()? - aRawConstraints.mVideo.GetAsObject() : - aRawConstraints.mAudio.GetAsObject())); + JS::Rooted audioObj (aCx, GetMandatoryJSObj(aRawConstraints.mAudio)); + JS::Rooted videoObj (aCx, GetMandatoryJSObj(aRawConstraints.mVideo)); + if (audioObj || videoObj) { + ac.construct(aCx, audioObj? audioObj : videoObj); } - // aRawConstraints has JSObjects in it, so process it by copying it into + // aRawConstraints may have JSObject in mMandatory, so copy everything into // MediaStreamConstraintsInternal which does not. dom::RootedDictionary c(aCx); + JS::Rooted 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); - // TODO: Simplify this part once Bug 767924 is fixed. - // Since we cannot yet use unions on non-objects, we process the raw object - // into discrete members for internal use until Bug 767924 is fixed + // Validate mandatory constraints by detecting any unknown constraints. + // Done by comparing the raw MediaTrackConstraints against the normalized copy - nsresult rv; nsString unknownConstraintFound; - - if (aRawConstraints.mAudio.IsObject()) { - JS::Rooted temp(aCx, - JS::ObjectValue(*aRawConstraints.mAudio.GetAsObject())); - bool success = c.mAudiom.Init(aCx, temp); - NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); - - rv = ValidateTrackConstraints(aCx, aRawConstraints.mAudio.GetAsObject(), - c.mAudiom, &unknownConstraintFound); + if (audioObj) { + nsresult rv = CompareDictionaries(aCx, audioObj, + c.mAudio.GetAsMediaTrackConstraintsInternal().mMandatory, + &unknownConstraintFound); NS_ENSURE_SUCCESS(rv, rv); - c.mAudio = true; - } else { - c.mAudio = aRawConstraints.mAudio.GetAsBoolean(); } - if (aRawConstraints.mVideo.IsObject()) { - JS::Rooted temp(aCx, - JS::ObjectValue(*aRawConstraints.mVideo.GetAsObject())); - bool success = c.mVideom.Init(aCx, temp); - NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); - - rv = ValidateTrackConstraints(aCx, aRawConstraints.mVideo.GetAsObject(), - c.mVideom, &unknownConstraintFound); + if (videoObj) { + nsresult rv = CompareDictionaries(aCx, videoObj, + c.mVideo.GetAsMediaTrackConstraintsInternal().mMandatory, + &unknownConstraintFound); NS_ENSURE_SUCCESS(rv, rv); - c.mVideo = true; - } else { - c.mVideo = aRawConstraints.mVideo.GetAsBoolean(); } - c.mPicture = aRawConstraints.mPicture; - c.mFake = aRawConstraints.mFake; /** * If we were asked to get a picture, before getting a snapshot, we check if @@ -1434,7 +1426,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, aPrivileged = true; } if (!Preferences::GetBool("media.navigator.video.enabled", true)) { - c.mVideo = false; + c.mVideo.SetAsBoolean() = false; } // Pass callbacks and MediaStreamListener along to GetUserMediaRunnable. @@ -1474,7 +1466,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, NS_ENSURE_SUCCESS(rv, rv); uint32_t audioPerm = nsIPermissionManager::UNKNOWN_ACTION; - if (c.mAudio) { + if (IsOn(c.mAudio)) { rv = permManager->TestExactPermissionFromPrincipal( aWindow->GetExtantDoc()->NodePrincipal(), "microphone", &audioPerm); NS_ENSURE_SUCCESS(rv, rv); @@ -1484,7 +1476,7 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, } uint32_t videoPerm = nsIPermissionManager::UNKNOWN_ACTION; - if (c.mVideo) { + if (IsOn(c.mVideo)) { rv = permManager->TestExactPermissionFromPrincipal( aWindow->GetExtantDoc()->NodePrincipal(), "camera", &videoPerm); NS_ENSURE_SUCCESS(rv, rv); @@ -1493,18 +1485,18 @@ MediaManager::GetUserMedia(JSContext* aCx, bool aPrivileged, } } - if ((!c.mAudio || audioPerm) && (!c.mVideo || videoPerm)) { + if ((!IsOn(c.mAudio) || audioPerm) && (!IsOn(c.mVideo) || videoPerm)) { // All permissions we were about to request already have a saved value. - if (c.mAudio && audioPerm == nsIPermissionManager::DENY_ACTION) { - c.mAudio = false; + if (IsOn(c.mAudio) && audioPerm == nsIPermissionManager::DENY_ACTION) { + c.mAudio.SetAsBoolean() = false; runnable->SetContraints(c); } - if (c.mVideo && videoPerm == nsIPermissionManager::DENY_ACTION) { - c.mVideo = false; + if (IsOn(c.mVideo) && videoPerm == nsIPermissionManager::DENY_ACTION) { + c.mVideo.SetAsBoolean() = false; runnable->SetContraints(c); } - if (!c.mAudio && !c.mVideo) { + if (!IsOn(c.mAudio) && !IsOn(c.mVideo)) { return runnable->Denied(NS_LITERAL_STRING("PERMISSION_DENIED")); } diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index 5dd99ff16d74..b1b9bc6a2c2e 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -21,6 +21,7 @@ #include "mozilla/Attributes.h" #include "mozilla/Preferences.h" #include "mozilla/StaticPtr.h" +#include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/MediaStreamTrackBinding.h" #include "prlog.h" #include "DOMMediaStream.h" diff --git a/dom/media/MediaPermissionGonk.cpp b/dom/media/MediaPermissionGonk.cpp index a49e59bba424..2f31a800916e 100644 --- a/dom/media/MediaPermissionGonk.cpp +++ b/dom/media/MediaPermissionGonk.cpp @@ -179,8 +179,8 @@ MediaPermissionRequest::MediaPermissionRequest(nsRefPtrGetConstraints(constraints); - mAudio = constraints.mAudio; - mVideo = constraints.mVideo; + mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean(); + mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean(); for (uint32_t i = 0; i < aDevices.Length(); ++i) { nsCOMPtr device(aDevices[i]); diff --git a/dom/webidl/MediaStream.webidl b/dom/webidl/MediaStream.webidl index 7c1cc6df8cdd..5bfcca752197 100644 --- a/dom/webidl/MediaStream.webidl +++ b/dom/webidl/MediaStream.webidl @@ -10,6 +10,23 @@ * liability, trademark and document use rules apply. */ +// These dictionaries need to be in a separate file from their +// MediaTrackConstraints* counterparts due to a webidl compiler limitation. + +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; +}; + interface MediaStream { // readonly attribute DOMString id; sequence getAudioTracks (); diff --git a/dom/webidl/MediaStreamTrack.webidl b/dom/webidl/MediaStreamTrack.webidl index 027099b90498..6dd49ced7b26 100644 --- a/dom/webidl/MediaStreamTrack.webidl +++ b/dom/webidl/MediaStreamTrack.webidl @@ -29,31 +29,13 @@ dictionary MediaTrackConstraintSet { // typedef MediaTrackConstraintSet MediaTrackConstraint; // TODO: Bug 913053 -dictionary MediaStreamConstraints { - (boolean or object) audio = false; // TODO: Once Bug 767924 fixed change to - (boolean or object) video = false; // (boolean or MediaTrackConstraints) - boolean picture = false; - boolean fake = false; -}; - -// Internal dictionary to process the raw objects in (boolean or object) -// workaround above. Since we cannot yet use unions on non-objects, we process -// the data into discrete members for internal use until Bug 767924 is fixed: - -dictionary MediaStreamConstraintsInternal { - boolean audio = false; - boolean video = false; - boolean picture = false; - boolean fake = false; - MediaTrackConstraintsInternal audiom; - MediaTrackConstraintsInternal videom; -}; - dictionary MediaTrackConstraints { object mandatory; // so we can see unknown + unsupported constraints sequence _optional; // a.k.a. MediaTrackConstraint }; +// Internal dictionary holds result of processing raw MediaTrackConstraints above + dictionary MediaTrackConstraintsInternal { MediaTrackConstraintSet mandatory; // holds only supported constraints sequence _optional; // a.k.a. MediaTrackConstraint