Bug 1006707 - change facingMode from enum to DOMString and support it as array. r=smaug, r=mt
authorJan-Ivar Bruaroey <jib@mozilla.com>
Wed, 21 Jan 2015 11:10:19 -0500
changeset 252222 da5679ebd7590fcb7e985b8940f3d8e3b9a9f9a2
parent 252221 04c4527643394e15b8fac110ecd9c5cfe4cb07b8
child 252223 9c237f7ff8b1e14f5ea44b755edc2ac13770cdee
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, mt
bugs1006707
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1006707 - change facingMode from enum to DOMString and support it as array. r=smaug, r=mt
CLOBBER
dom/media/MediaManager.cpp
dom/media/tests/mochitest/constraints.js
dom/media/tests/mochitest/mochitest.ini
dom/media/tests/mochitest/test_getUserMedia_exceptions.html
dom/media/webrtc/MediaTrackConstraints.h
dom/webidl/Constraints.webidl
dom/webidl/MediaStreamTrack.webidl
dom/webidl/MediaTrackConstraintSet.webidl
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1115998 - (DOMString or sequence<DOMString>) needs binding flush (Bug 1103153)
+Bug 1006707 - (DOMString or sequence<DOMString>) needs binding flush (Bug 1103153)
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -434,27 +434,32 @@ VideoDevice::VideoDevice(MediaEngineVide
 bool
 VideoDevice::SatisfiesConstraintSets(
     const nsTArray<const MediaTrackConstraintSet*>& aConstraintSets)
 {
   // Interrogate device-inherent properties first.
   for (size_t i = 0; i < aConstraintSets.Length(); i++) {
     auto& c = *aConstraintSets[i];
     if (c.mFacingMode.WasPassed()) {
+      auto& value = c.mFacingMode.Value();
       nsString s;
       GetFacingMode(s);
-      if (!s.EqualsASCII(dom::VideoFacingModeEnumValues::strings[
-          static_cast<uint32_t>(c.mFacingMode.Value())].value)) {
-        return false;
+      if (value.IsString()) {
+        if (s != value.GetAsString()) {
+          return false;
+        }
+      } else {
+        if (!value.GetAsStringSequence().Contains(s)) {
+          return false;
+        }
       }
     }
     nsString s;
     GetMediaSource(s);
-    if (!s.EqualsASCII(dom::MediaSourceEnumValues::strings[
-        static_cast<uint32_t>(c.mMediaSource)].value)) {
+    if (s != c.mMediaSource) {
       return false;
     }
   }
   // Forward request to underlying object to interrogate per-mode capabilities.
   return GetSource()->SatisfiesConstraintSets(aConstraintSets);
 }
 
 AudioDevice::AudioDevice(MediaEngineAudioSource* aSource)
@@ -951,17 +956,19 @@ static void
   typedef nsTArray<nsRefPtr<DeviceType>> SourceSet;
 
   nsString deviceName;
   // First collect sources
   SourceSet candidateSet;
   {
     nsTArray<nsRefPtr<typename DeviceType::Source> > sources;
     // all MediaSourceEnums are contained in MediaSourceType
-    (engine->*aEnumerate)((MediaSourceType)((int)aConstraints.mMediaSource), &sources);
+
+    (engine->*aEnumerate)((MediaSourceType)(aConstraints.mMediaSourceEnumValue),
+                          &sources);
     /**
       * We're allowing multiple tabs to access the same camera for parity
       * with Chrome.  See bug 811757 for some of the issues surrounding
       * this decision.  To disallow, we'd filter by IsAvailable() as we used
       * to.
       */
     for (uint32_t len = sources.Length(), i = 0; i < len; i++) {
       sources[i]->GetName(deviceName);
@@ -1625,42 +1632,43 @@ MediaManager::GetUserMedia(
   }
 
 #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() &&
         tc.mMandatory.mFacingMode.WasPassed() && !tc.mFacingMode.WasPassed()) {
-      tc.mFacingMode.Construct(tc.mMandatory.mFacingMode.Value());
+      tc.mFacingMode.Construct().SetAsString() = 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++) {
+      for (size_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());
+          n.mFacingMode.Construct().SetAsString() =
+              tc.mOptional.Value()[i].mFacingMode.Value();
           tc.mAdvanced.Value().AppendElement(n);
         }
       }
     }
   }
 #endif
 
   if (c.mVideo.IsMediaTrackConstraints() && !privileged) {
     auto& tc = c.mVideo.GetAsMediaTrackConstraints();
     // only allow privileged content to set the window id
     if (tc.mBrowserWindow.WasPassed()) {
       tc.mBrowserWindow.Construct(-1);
     }
 
     if (tc.mAdvanced.WasPassed()) {
-      uint32_t length = tc.mAdvanced.Value().Length();
-      for (uint32_t i = 0; i < length; i++) {
+      size_t length = tc.mAdvanced.Value().Length();
+      for (size_t i = 0; i < length; i++) {
         if (tc.mAdvanced.Value()[i].mBrowserWindow.WasPassed()) {
           tc.mAdvanced.Value()[i].mBrowserWindow.Construct(-1);
         }
       }
     }
   }
 
   // Pass callbacks and MediaStreamListener along to GetUserMediaTask.
@@ -1674,43 +1682,55 @@ MediaManager::GetUserMedia(
     task = new GetUserMediaTask(c, onSuccess.forget(),
       onFailure.forget(), windowID, listener, mPrefs);
   }
 
   nsIURI* docURI = aWindow->GetDocumentURI();
 
   if (c.mVideo.IsMediaTrackConstraints()) {
     auto& tc = c.mVideo.GetAsMediaTrackConstraints();
-    // deny screensharing request if support is disabled
-    if (tc.mMediaSource != dom::MediaSourceEnum::Camera) {
-      if (tc.mMediaSource == dom::MediaSourceEnum::Browser) {
-        if (!Preferences::GetBool("media.getusermedia.browser.enabled", false)) {
-          return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
-        }
-      } else if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
-        return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
-      }
-      /* Deny screensharing if the requesting document is not from a host
-       on the whitelist. */
-      // Block screen/window sharing on Mac OSX 10.6 and WinXP until proved that they work
-      if (
+    MediaSourceEnum src = StringToEnum(dom::MediaSourceEnumValues::strings,
+                                       tc.mMediaSource,
+                                       dom::MediaSourceEnum::Other);
+    switch (src) {
+    case dom::MediaSourceEnum::Camera:
+      break;
+
+    case dom::MediaSourceEnum::Browser:
+    case dom::MediaSourceEnum::Screen:
+    case dom::MediaSourceEnum::Application:
+    case dom::MediaSourceEnum::Window:
+      // Deny screensharing request if support is disabled, or
+      // the requesting document is not from a host on the whitelist, or
+      // we're on Mac OSX 10.6 and WinXP until proved that they work
+      if (!Preferences::GetBool(((src == dom::MediaSourceEnum::Browser)?
+                                "media.getusermedia.browser.enabled" :
+                                "media.getusermedia.screensharing.enabled"),
+                                false) ||
 #if defined(XP_MACOSX) || defined(XP_WIN)
           (
-            !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms", false) &&
+            !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms",
+                                  false) &&
 #if defined(XP_MACOSX)
             !nsCocoaFeatures::OnLionOrLater()
 #endif
 #if defined (XP_WIN)
             !IsVistaOrLater()
 #endif
-           ) ||
+            ) ||
 #endif
           (!privileged && !HostHasPermission(*docURI))) {
         return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
       }
+      break;
+
+    case dom::MediaSourceEnum::Microphone:
+    case dom::MediaSourceEnum::Other:
+    default:
+      return task->Denied(NS_LITERAL_STRING("NotFoundError"));
     }
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
   }
 #endif
--- a/dom/media/tests/mochitest/constraints.js
+++ b/dom/media/tests/mochitest/constraints.js
@@ -18,34 +18,52 @@ var common_tests = [
   { message: "unknown required constraint on audio fails",
     constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] },
                    fake: true },
     error: "NotFoundError" },
   { message: "video overconstrained by facingMode fails",
     constraints: { video: { facingMode:'left', require:["facingMode"] },
                    fake: true },
     error: "NotFoundError" },
+  { message: "video overconstrained by facingMode array fails",
+    constraints: { video: { facingMode:['left', 'right'], require:["facingMode"] },
+                   fake: true },
+    error: "NotFoundError" },
   { message: "audio overconstrained by facingMode fails",
     constraints: { audio: { facingMode:'left', require:["facingMode"] },
                    fake: true },
     error: "NotFoundError" },
+  { message: "full screensharing requires permission",
+    constraints: { video: { mediaSource:'screen' } },
+    error: "PermissionDeniedError" },
+  { message: "application screensharing requires permission",
+    constraints: { video: { mediaSource:'application' } },
+    error: "PermissionDeniedError" },
+  { message: "window screensharing requires permission",
+    constraints: { video: { mediaSource:'window' } },
+    error: "PermissionDeniedError" },
+  { message: "browser screensharing requires permission",
+    constraints: { video: { mediaSource:'browser' } },
+    error: "PermissionDeniedError" },
+  { message: "unknown mediaSource fails",
+    constraints: { video: { mediaSource:'uncle' } },
+    error: "NotFoundError" },
   { message: "Success-path: optional video facingMode + audio ignoring facingMode",
     constraints: { fake: true,
-                   audio: { facingMode:'left',
+                   audio: { mediaSource:'microphone',
+                            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',
+                   video: { mediaSource:'camera',
+                            facingMode:['left', 'right', 'user', 'environment'],
                             foo:0,
                             advanced: [{ facingMode:'environment' },
-                                       { facingMode:'user' },
+                                       { facingMode:['user'] },
                                        { bar:0 }] } },
     error: null }
 ];
 
 
 /**
  * Starts the test run by running through each constraint
  * test by verifying that the right resolution and rejection is fired.
@@ -58,17 +76,19 @@ function testConstraints(tests) {
     })
     .then(function() {
       is(null, test.error, test.message);
     }, function(reason) {
       is(reason.name, test.error, test.message + ": " + reason.message);
     });
   }
 
-  var p = new Promise(function(resolve) { resolve(); });
+  var p = new Promise(r => SpecialPowers.pushPrefEnv({
+      set : [ ['media.getusermedia.browser.enabled', false],
+              ['media.getusermedia.screensharing.enabled', false] ]
+    }, r));
+
   tests.forEach(function(test) {
     p = testgum(p, test);
   });
-  p.catch(function(reason) {
-    ok(false, "Unexpected failure: " + reason.message);
-  })
+  p.catch(reason => ok(false, "Unexpected failure: " + reason.message))
   .then(SimpleTest.finish);
 }
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -38,17 +38,16 @@ skip-if = buildapp == 'b2g' || toolkit =
 [test_getUserMedia_basicWindowshare.html]
 skip-if = buildapp == 'b2g' || toolkit == 'android' # no windowshare on b2g/android
 [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]
 [test_getUserMedia_playVideoAudioTwice.html]
 skip-if = (toolkit == 'gonk' && debug) # debug-only failure; bug 926558
 [test_getUserMedia_playVideoTwice.html]
 [test_getUserMedia_stopAudioStream.html]
 [test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
 [test_getUserMedia_stopVideoAudioStream.html]
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_exceptions.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=795367
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test mozGetUserMedia Exceptions</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>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=795367">Test mozGetUserMedia Exceptions</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script type="application/javascript">
-/**
-  These tests verify that the appropriate exception is thrown when incorrect
-  values are provided to the immediate mozGetUserMedia call.
-*/
-var exceptionTests = [
-  // Each test here verifies that a caller is required to have all
-  // three arguments in order to call mozGetUserMedia
-  { params: undefined,
-    error: "Not enough arguments to Navigator.mozGetUserMedia.",
-    message: "no arguments specified" },
-  { params: [{video: true, fake: true}],
-    error: "Not enough arguments to Navigator.mozGetUserMedia.",
-    message: "one argument specified" },
-  { params: [{video: true, fake: true}, unexpectedCall],
-    error: "Not enough arguments to Navigator.mozGetUserMedia.",
-    message: "two arguments specified" },
-
-  // Each test here verifies that providing an incorret object
-  // type to any mozGetUserMedia parameter should throw
-  // the correct exception specified
-  { params: [1, unexpectedCall, unexpectedCall],
-    error: "Argument 1 of Navigator.mozGetUserMedia can't be converted to a dictionary.",
-    message: "wrong object type as first parameter" },
-  { params: [{video: true, fake: true}, 1, unexpectedCall],
-    error: "Argument 2 of Navigator.mozGetUserMedia is not an object.",
-    message: "wrong object type as second parameter" },
-  { params: [{video: true, fake: true}, unexpectedCall, 1],
-    error: "Argument 3 of Navigator.mozGetUserMedia is not an object.",
-    message: "wrong object type as third parameter" },
-
-  // Each test here verifies constraint syntax as defined in webidl
-  { 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" }
-];
-
-/**
- * A callback function that is only called if a particular
- * exception was not thrown, resulting in the test failing.
- *
- * @param  {MediaStream} argument ignored
- */
-function unexpectedCall(obj) {
-  ok(false, "Callback should not have been called");
-}
-
-/**
- * Starts the test run by running through each exception
- * test by verifying that the correct exception type specified
- * is thrown on the mozGetUserMedia call with the parameters
- * specified.
- */
-runTest(function () {
-  exceptionTests.forEach(function (test) {
-    var exception = false;
-    try {
-      navigator.mozGetUserMedia.apply(navigator, test.params);
-    } catch (e) {
-      exception = (e.message === test.error);
-      if(!exception) {
-        info(e.message);
-      }
-    }
-    ok(exception, "Exception for " + test.message);
-  });
-
-  SimpleTest.finish();
-});
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/media/webrtc/MediaTrackConstraints.h
+++ b/dom/media/webrtc/MediaTrackConstraints.h
@@ -7,81 +7,94 @@
 #ifndef MEDIATRACKCONSTRAINTS_H_
 #define MEDIATRACKCONSTRAINTS_H_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
 
 namespace mozilla {
 
+template<class EnumValuesStrings, class Enum>
+static const char* EnumToASCII(const EnumValuesStrings& aStrings, Enum aValue) {
+  return aStrings[uint32_t(aValue)].value;
+}
+
+template<class EnumValuesStrings, class Enum>
+static Enum StringToEnum(const EnumValuesStrings& aStrings, const nsAString& aValue,
+                         Enum aDefaultValue) {
+  for (size_t i = 0; aStrings[i].value; i++) {
+    if (aValue.EqualsASCII(aStrings[i].value)) {
+      return Enum(i);
+    }
+  }
+  return aDefaultValue;
+}
+
 // Normalized internal version of MediaTrackConstraints to simplify downstream
 // processing. This implementation-only helper is included as needed by both
 // MediaManager (for gUM camera selection) and MediaEngine (for applyConstraints).
 
 template<typename T>
 class MediaTrackConstraintsN : public dom::MediaTrackConstraints
 {
 public:
   typedef T Kind;
   dom::Sequence<Kind> mRequireN;
   bool mUnsupportedRequirement;
   MediaTrackConstraintSet mRequired;
   dom::Sequence<MediaTrackConstraintSet> mNonrequired;
+  dom::MediaSourceEnum mMediaSourceEnumValue;
 
   MediaTrackConstraintsN(const dom::MediaTrackConstraints &aOther,
                          const dom::EnumEntry* aStrings)
   : dom::MediaTrackConstraints(aOther)
   , mUnsupportedRequirement(false)
   , mStrings(aStrings)
   {
     if (mRequire.WasPassed()) {
       auto& array = mRequire.Value();
-      for (uint32_t i = 0; i < array.Length(); i++) {
-        auto value = ToEnum(array[i]);
+      for (size_t i = 0; i < array.Length(); i++) {
+        auto value = StringToEnum(mStrings, array[i], Kind::Other);
         if (value != Kind::Other) {
           mRequireN.AppendElement(value);
         } else {
           mUnsupportedRequirement = true;
         }
       }
     }
-
     // treat MediaSource special because it's always required
     mRequired.mMediaSource = mMediaSource;
 
-    // we guarantee (int) equivalence from MediaSourceEnum ->MediaSourceType
-    // (but not the other way)
-    if (mMediaSource != dom::MediaSourceEnum::Camera && mAdvanced.WasPassed()) {
-      // iterate through advanced, forcing mediaSource to match "root"
-      auto& array = mAdvanced.Value();
-      for (uint32_t i = 0; i < array.Length(); i++) {
-        if (array[i].mMediaSource == dom::MediaSourceEnum::Camera) {
-          array[i].mMediaSource = mMediaSource;
+    mMediaSourceEnumValue = StringToEnum(dom::MediaSourceEnumValues::strings,
+                                         mMediaSource,
+                                         dom::MediaSourceEnum::Other);
+    if (mAdvanced.WasPassed()) {
+      if(mMediaSourceEnumValue != dom::MediaSourceEnum::Camera) {
+        // iterate through advanced, forcing mediaSource to match "root"
+        auto& array = mAdvanced.Value();
+        for (uint32_t i = 0; i < array.Length(); i++) {
+          auto& ms = array[i].mMediaSource;
+          if (ms.EqualsASCII(EnumToASCII(dom::MediaSourceEnumValues::strings,
+                                         dom::MediaSourceEnum::Camera))) {
+            ms = mMediaSource;
+          }
         }
       }
     }
   }
 protected:
   MediaTrackConstraintSet& Triage(const Kind kind) {
     if (mRequireN.IndexOf(kind) != mRequireN.NoIndex) {
       return mRequired;
     } else {
       mNonrequired.AppendElement(MediaTrackConstraintSet());
       return mNonrequired[mNonrequired.Length()-1];
     }
   }
 private:
-  Kind ToEnum(const nsAString& aSrc) {
-    for (size_t i = 0; mStrings[i].value; i++) {
-      if (aSrc.EqualsASCII(mStrings[i].value)) {
-        return Kind(i);
-      }
-    }
-    return Kind::Other;
-  }
   const dom::EnumEntry* mStrings;
 };
 
 struct AudioTrackConstraintsN :
   public MediaTrackConstraintsN<dom::SupportedAudioConstraints>
 {
   MOZ_IMPLICIT AudioTrackConstraintsN(const dom::MediaTrackConstraints &aOther)
   : MediaTrackConstraintsN<dom::SupportedAudioConstraints>(aOther, // B2G ICS compiler bug
--- a/dom/webidl/Constraints.webidl
+++ b/dom/webidl/Constraints.webidl
@@ -2,29 +2,35 @@
 /* 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/.
  */
 
 // These dictionaries need to be in a separate file from their use in unions
 // in MediaTrackConstraintSet.webidl due to a webidl compiler limitation.
 
+// These enums are in the spec even though they're not used directly in the API
+// due to https://www.w3.org/Bugs/Public/show_bug.cgi?id=19936
+// Their binding code is quite useful though, and is used in the implementation.
+
 enum VideoFacingModeEnum {
     "user",
     "environment",
     "left",
     "right"
 };
 
 enum MediaSourceEnum {
     "camera",
     "screen",
     "application",
     "window",
-    "browser"
+    "browser",
+    "microphone",
+    "other"
 };
 
 dictionary ConstrainLongRange {
     long min = -2147483647; // +1 works around windows compiler bug
     long max = 2147483647;
 };
 
 dictionary ConstrainDoubleRange {
--- a/dom/webidl/MediaStreamTrack.webidl
+++ b/dom/webidl/MediaStreamTrack.webidl
@@ -16,17 +16,17 @@ dictionary MediaTrackConstraints : Media
 
     // mobile-only backwards-compatibility for facingMode
     MobileLegacyMediaTrackConstraintSet mandatory;
     sequence<MobileLegacyMediaTrackConstraintSet> _optional;
 };
 
 // TODO(jib): Remove in 6+ weeks (Bug 997365)
 dictionary MobileLegacyMediaTrackConstraintSet {
-    VideoFacingModeEnum facingMode;
+    DOMString facingMode;
 };
 
 interface MediaStreamTrack {
     readonly    attribute DOMString             kind;
     readonly    attribute DOMString             id;
     readonly    attribute DOMString             label;
                 attribute boolean               enabled;
 //    readonly    attribute MediaStreamTrackState readyState;
--- a/dom/webidl/MediaTrackConstraintSet.webidl
+++ b/dom/webidl/MediaTrackConstraintSet.webidl
@@ -17,29 +17,21 @@ enum SupportedVideoConstraints {
     "browserWindow",
     "scrollWithPage"
 };
 
 enum SupportedAudioConstraints {
     "other"
 };
 
-
 dictionary MediaTrackConstraintSet {
     ConstrainLongRange width;
     ConstrainLongRange height;
     ConstrainDoubleRange frameRate;
-    ConstrainVideoFacingMode facingMode;
-    ConstrainMediaSource mediaSource = "camera";
+    ConstrainDOMString facingMode;
+    DOMString mediaSource = "camera";
     long long browserWindow;
     boolean scrollWithPage;
 };
 
-// TODO: Bug 995352 can't nest unions
-//typedef (long or ConstrainLongRange) ConstrainLong;
-//typedef (double or ConstrainDoubleRange) ConstrainDouble;
-
-typedef VideoFacingModeEnum ConstrainVideoFacingMode;
-typedef MediaSourceEnum ConstrainMediaSource;
-
-// TODO: Bug 767924 sequences in unions
-//typedef (VideoFacingModeEnum or sequence<VideoFacingModeEnum>) ConstrainVideoFacingMode;
-//typedef (MediaSourceEnum or sequence<MediaSourceEnum>) ConstrainMediaSource;
\ No newline at end of file
+typedef (long or ConstrainLongRange) ConstrainLong;
+typedef (double or ConstrainDoubleRange) ConstrainDouble;
+typedef (DOMString or sequence<DOMString>) ConstrainDOMString;