Bug 907352 - Part 2: Backwards-compatible facingMode constraint on mobile. r=mt, r=drno
authorJan-Ivar Bruaroey <jib@mozilla.com>
Fri, 18 Apr 2014 15:14:23 -0400
changeset 198940 a8aea4c4977e072fcbe56f63ad092cf811685866
parent 198939 abd958ec8fec919fc85f923d07ce471a6ca5c5da
child 198941 c0b31eca151e8bf2a9b2371b826f3ce10c445436
push id3624
push userasasaki@mozilla.com
push dateMon, 09 Jun 2014 21:49:01 +0000
treeherdermozilla-beta@b1a5da15899a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmt, drno
bugs907352
milestone31.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 907352 - Part 2: Backwards-compatible facingMode constraint on mobile. r=mt, r=drno
dom/media/MediaManager.cpp
dom/media/tests/mochitest/constraints.js
dom/media/tests/mochitest/mochitest.ini
dom/media/tests/mochitest/test_getUserMedia_constraints.html
dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html
dom/webidl/MediaStreamTrack.webidl
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1427,16 +1427,40 @@ MediaManager::GetUserMedia(bool aPrivile
   // Developer preference for turning off permission check.
   if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
     aPrivileged = true;
   }
   if (!Preferences::GetBool("media.navigator.video.enabled", true)) {
     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) {
     // Fake stream from default backend.
     runnable = new GetUserMediaRunnable(c, onSuccess.forget(),
       onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
   } else {
     // Stream from default device from WebRTC backend.
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/constraints.js
@@ -0,0 +1,82 @@
+/* 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"] },
+                   fake: true },
+    error: "NO_DEVICES_FOUND" },
+  { message: "unknown required constraint on audio fails",
+    constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] },
+                   fake: true },
+    error: "NO_DEVICES_FOUND" },
+  { message: "missing required constraint on video fails",
+    constraints: { video: { require:["facingMode"] }, fake: true },
+    error: "NO_DEVICES_FOUND" },
+  { message: "missing required constraint on audio fails",
+    constraints: { audio: { require:["facingMode"] }, fake: true },
+    error: "NO_DEVICES_FOUND" },
+  { message: "video overconstrained by facingMode fails",
+    constraints: { video: { facingMode:'left', require:["facingMode"] },
+                   fake: true },
+    error: "NO_DEVICES_FOUND" },
+  { message: "audio overconstrained by facingMode fails",
+    constraints: { audio: { facingMode:'left', require:["facingMode"] },
+                   fake: true },
+    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();
+    }
+  }
+};
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -1,11 +1,12 @@
 [DEFAULT]
 support-files =
   head.js
+  constraints.js
   mediaStreamPlayback.js
   pc.js
   templates.js
   NetworkPreparationChromeScript.js
 
 [test_dataChannel_basicAudio.html]
 skip-if = (toolkit == 'gonk' && debug) #Bug 962984, test fail on b2g debug build
 [test_dataChannel_basicAudioVideo.html]
@@ -20,16 +21,19 @@ skip-if = toolkit=='gonk' # b2g(Bug 9604
 [test_dataChannel_noOffer.html]
 [test_getUserMedia_basicAudio.html]
 skip-if = (toolkit == 'gonk' && debug) #debug-only failure
 [test_getUserMedia_basicVideo.html]
 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]
 [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]
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html
@@ -4,116 +4,37 @@
 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</a>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=882145">Test mozGetUserMedia Constraints (desktop)</a>
 <p id="display"></p>
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="application/javascript">
 /**
-  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.
+  See constraints.js for testConstraints() and common_tests.
+  TODO(jib): Merge desktop and mobile version of these tests again (Bug 997365)
 */
-var tests = [
-  // Each test here tests a different constraint or codepath.
-  { message: "unknown required constraint on video fails",
-    constraints: { video: { somethingUnknown:0, require:["somethingUnknown"] },
-                   fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { message: "unknown required constraint on audio fails",
-    constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] },
-                   fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { message: "missing required constraint on video fails",
-    constraints: { video: { require:["facingMode"] }, fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { message: "missing required constraint on audio fails",
-    constraints: { audio: { require:["facingMode"] }, fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { message: "video overconstrained by facingMode fails",
-    constraints: { video: { facingMode:'left', require:["facingMode"] },
-                   fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { message: "audio overconstrained by facingMode fails",
-    constraints: { audio: { facingMode:'left', require:["facingMode"] },
-                   fake: true },
-    error: "NO_DEVICES_FOUND",
-    pass: false },
-  { 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,
-    pass: false },
-  { message: null },
+var desktop_tests = [
+  { message: "legacy facingMode ignored (desktop)",
+    constraints: { video: { mandatory: { facingMode:'left' } }, fake: true },
+    error: null },
 ];
 
-/**
- * Starts the test run by running through each constraint
- * test by verifying that the right callback and error message is fired.
- */
-
 runTest(function () {
-  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();
-      }
-    });
-  }
+  testConstraints(common_tests.concat(desktop_tests));
 });
 
 
 </script>
 </pre>
 </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html
@@ -0,0 +1,40 @@
+<!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' } }, fake: true },
+    error: "NO_DEVICES_FOUND" },
+];
+
+runTest(function () {
+  testConstraints(common_tests.concat(mobile_tests));
+});
+
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/MediaStreamTrack.webidl
+++ b/dom/webidl/MediaStreamTrack.webidl
@@ -27,19 +27,27 @@ enum SupportedVideoConstraints {
 enum SupportedAudioConstraints {
     "dummy"
 };
 
 dictionary MediaTrackConstraintSet {
     ConstrainVideoFacingMode facingMode;
 };
 
+dictionary MobileLegacyMediaTrackConstraintSet {
+    VideoFacingModeEnum facingMode;
+};
+
 dictionary MediaTrackConstraints : MediaTrackConstraintSet {
     sequence<DOMString> require;
     sequence<MediaTrackConstraintSet> advanced;
+
+    // mobile-only backwards-compatibility for facingMode
+    MobileLegacyMediaTrackConstraintSet mandatory;
+    sequence<MobileLegacyMediaTrackConstraintSet> _optional;
 };
 
 typedef VideoFacingModeEnum ConstrainVideoFacingMode;
 // TODO: Bug 767924 sequences in unions
 //typedef (VideoFacingModeEnum or sequence<VideoFacingModeEnum>) ConstrainVideoFacingMode;
 
 interface MediaStreamTrack {
     readonly    attribute DOMString             kind;