Update WPT mediacapture-streams tests
authoreric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2019 19:24:55 +0000 (19:24 +0000)
committereric.carlson@apple.com <eric.carlson@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 11 Nov 2019 19:24:55 +0000 (19:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204073

Reviewed by Youenn Fablet.

LayoutTests/imported/w3c:

* resources/import-expectations.json:
* web-platform-tests/mediacapture-streams/GUM-deny.https.html:
* web-platform-tests/mediacapture-streams/GUM-impossible-constraint.https.html:
* web-platform-tests/mediacapture-streams/GUM-optional-constraint.https.html:
* web-platform-tests/mediacapture-streams/GUM-trivial-constraint.https.html:
* web-platform-tests/mediacapture-streams/MediaDevices-IDL-all-expected.txt: Removed.
* web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html: Removed.
* web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt: Removed.
* web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html: Removed.
* web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html:
* web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https-expected.txt: Removed.
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html: Removed.
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-add-audio-track.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-audio-only.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-finished-add.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-gettrackid.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-idl.https.html:
* web-platform-tests/mediacapture-streams/MediaStream-removetrack.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStream-removetrack.https.html:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https.html:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https.html:
* web-platform-tests/mediacapture-streams/MediaStreamTrack-id.https.html:
* web-platform-tests/mediacapture-streams/OWNERS: Removed.
* web-platform-tests/mediacapture-streams/historical.html: Removed.
* web-platform-tests/mediacapture-streams/w3c-import.log:

LayoutTests:

* tests-options.json:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252335 268f45cc-cd09-0410-ab3c-d52691b4dbfc

71 files changed:
LayoutTests/ChangeLog
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/resources/import-expectations.json
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-deny.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-impossible-constraint.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-optional-constraint.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-trivial-constraint.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/META.yml [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all-expected.txt [deleted file]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html [deleted file]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt [deleted file]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html [deleted file]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html.headers [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html.headers [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https-expected.txt [moved from LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https-expected.txt with 63% similarity]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https.html [moved from LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html with 84% similarity]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-add-audio-track.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-audio-only.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-finished-add.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-gettrackid.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-idl.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-removetrack.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-removetrack.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-id.https.html
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/OWNERS [deleted file]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.https-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.https.html [moved from LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.html with 54% similarity]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window-expected.txt [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.html [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.js [new file with mode: 0644]
LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/w3c-import.log
LayoutTests/tests-options.json

index c0f01fd..7475bde 100644 (file)
@@ -1,3 +1,12 @@
+2019-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        Update WPT mediacapture-streams tests
+        https://bugs.webkit.org/show_bug.cgi?id=204073
+
+        Reviewed by Youenn Fablet.
+
+        * tests-options.json:
+
 2019-11-11  Peng Liu  <peng.liu6@apple.com>
 
         [Picture-in-Picture Web API] Support picture-in-picture CSS pseudo-class
index e205691..00474ca 100644 (file)
@@ -1,3 +1,48 @@
+2019-11-11  Eric Carlson  <eric.carlson@apple.com>
+
+        Update WPT mediacapture-streams tests
+        https://bugs.webkit.org/show_bug.cgi?id=204073
+
+        Reviewed by Youenn Fablet.
+
+        * resources/import-expectations.json:
+        * web-platform-tests/mediacapture-streams/GUM-deny.https.html:
+        * web-platform-tests/mediacapture-streams/GUM-impossible-constraint.https.html:
+        * web-platform-tests/mediacapture-streams/GUM-optional-constraint.https.html:
+        * web-platform-tests/mediacapture-streams/GUM-trivial-constraint.https.html:
+        * web-platform-tests/mediacapture-streams/MediaDevices-IDL-all-expected.txt: Removed.
+        * web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html: Removed.
+        * web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt: Removed.
+        * web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html: Removed.
+        * web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html:
+        * web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https-expected.txt: Removed.
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html: Removed.
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-add-audio-track.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-audio-only.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-finished-add.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-gettrackid.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-idl.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStream-removetrack.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStream-removetrack.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https-expected.txt:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https.html:
+        * web-platform-tests/mediacapture-streams/MediaStreamTrack-id.https.html:
+        * web-platform-tests/mediacapture-streams/OWNERS: Removed.
+        * web-platform-tests/mediacapture-streams/historical.html: Removed.
+        * web-platform-tests/mediacapture-streams/w3c-import.log:
+
 2019-11-08  youenn fablet  <youenn@apple.com>
 
         XMLHttpRequestUpload should be exposed in dedicated workers
index a6784c4..3503373 100644 (file)
     "web-platform-tests/mediacapture-image": "skip", 
     "web-platform-tests/mediacapture-record": "import", 
     "web-platform-tests/mediacapture-streams": "import", 
+    "web-platform-tests/mediacapture-streams/": "import", 
     "web-platform-tests/mediasession": "skip", 
     "web-platform-tests/microdata": "skip", 
     "web-platform-tests/mimesniff": "import", 
index 1744099..be1caf5 100644 (file)
@@ -16,7 +16,7 @@
   <script src=/resources/testharness.js></script>
   <script src=/resources/testharnessreport.js></script>
   <script>
-    var t = async_test("Tests that the error callback is triggered when permission is denied", {timeout:10000});
+    var t = async_test("Tests that the error callback is triggered when permission is denied");
     t.step(function() {
       navigator.mediaDevices.getUserMedia({video: true})
         .then(t.step_func(function (stream) {
index 13f3856..08442bb 100644 (file)
@@ -16,7 +16,7 @@ constraint (width &gt;=1G) in getUserMedia works</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that setting an impossible constraint in getUserMedia fails", {timeout:10000});
+var t = async_test("Tests that setting an impossible constraint in getUserMedia fails");
 t.step(function() {
   // Note - integer conversion is weird for +inf and numbers > 2^32, so we
   // use a number less than 2^32 for testing.
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https-expected.txt
new file mode 100644 (file)
index 0000000..fc4ce70
--- /dev/null
@@ -0,0 +1,7 @@
+Description
+
+This test checks that trying to set an empty facingMode value in getUserMedia results in an OverconstrainedError.
+
+
+FAIL Tests that setting an invalid facingMode constraint in getUserMedia fails assert_equals: expected "OverconstrainedError" but got "Error"
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https.html
new file mode 100644 (file)
index 0000000..d29caeb
--- /dev/null
@@ -0,0 +1,31 @@
+<!doctype html>
+<html>
+<head>
+<title>Invalid facingMode in getUserMedia</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#def-constraint-facingMode">
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that trying to set an empty facingMode
+  value in getUserMedia results in an OverconstrainedError.
+</p>
+
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+var t = async_test(
+  "Tests that setting an invalid facingMode constraint in getUserMedia fails");
+t.step(function() {
+  navigator.mediaDevices.getUserMedia({video: {facingMode: {exact: ''}}})
+    .then(t.step_func(function (stream) {
+      assert_unreached("The empty string is not a valid facingMode");
+      t.done();
+    }), t.step_func(function(error) {
+      assert_equals(error.name, "OverconstrainedError");
+      assert_equals(error.constraint, "facingMode");
+      t.done();
+    }));
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https-expected.txt
new file mode 100644 (file)
index 0000000..49b3b92
--- /dev/null
@@ -0,0 +1,8 @@
+When prompted, accept to share your audio and video stream.
+
+
+PASS Test that setting video-only valid constraints inside of "audio" is simply ignored 
+PASS Test that setting video-only invalid constraints inside of "audio" is simply ignored 
+PASS Test that setting audio-only valid constraints inside of "video" is simply ignored 
+PASS Test that setting audio-only invalid constraints inside of "video" is simply ignored 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https.html
new file mode 100644 (file)
index 0000000..8423c56
--- /dev/null
@@ -0,0 +1,72 @@
+<!doctype html>
+<title>non-applicable constraint in getUserMedia</title>
+<link rel="author" title="Intel" href="http://www.intel.com"/>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#methods-5">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<p class="instructions">When prompted, accept to share your audio and video stream.</p>
+
+<script>
+
+let video_only_valid_constraints = {
+  width: {min: 0},
+  height: {min: 0},
+  frameRate: {min: 0},
+  aspectRatio: {min: 0},
+  facingMode: {ideal: 'environment'},
+  resizeMode: {ideal: 'none'}
+}
+
+let video_only_invalid_constraints = {
+  width: {min: 100000000},
+  height: {min: 100000000},
+  frameRate: {min: 100000000},
+  aspectRatio: {min: 100000000},
+  facingMode: {exact: 'invalid'},
+  resizeMode: {exact: 'invalid'}
+}
+
+let audio_only_valid_constraints = {
+  volume: {min: 0},
+  sampleRate: {min: 0},
+  sampleSize: {min: 0},
+  echoCancellation: {ideal: true},
+  autoGainControl: {ideal: true},
+  noiseSuppression: {ideal: true},
+  latency: {min: 0},
+  channelCount: {min: 0}
+}
+
+let audio_only_invalid_constraints = {
+  volume: {min: 2},
+  sampleRate: {min: 100000000},
+  sampleSize: {min: 100000000},
+  echoCancellation: {exact: true},
+  autoGainControl: {exact: true},
+  noiseSuppression: {exact: true},
+  latency: {max: 0},
+  channelCount: {max: 0}
+}
+
+promise_test(async () => {
+  let stream = await navigator.mediaDevices.getUserMedia({audio: video_only_valid_constraints})
+  assert_equals(stream.getAudioTracks().length, 1, "the media stream has exactly one audio track");
+}, 'Test that setting video-only valid constraints inside of "audio" is simply ignored');
+
+promise_test(async () => {
+  let stream = await navigator.mediaDevices.getUserMedia({audio: video_only_invalid_constraints})
+  assert_equals(stream.getAudioTracks().length, 1, "the media stream has exactly one audio track");
+}, 'Test that setting video-only invalid constraints inside of "audio" is simply ignored');
+
+promise_test(async () => {
+  let stream = await navigator.mediaDevices.getUserMedia({video: audio_only_valid_constraints})
+  assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+}, 'Test that setting audio-only valid constraints inside of "video" is simply ignored');
+
+promise_test(async () => {
+  let stream = await navigator.mediaDevices.getUserMedia({video: audio_only_invalid_constraints})
+  assert_equals(stream.getVideoTracks().length, 1, "the media stream has exactly one video track");
+}, 'Test that setting audio-only invalid constraints inside of "video" is simply ignored');
+
+</script>
index becd871..28b9767 100644 (file)
@@ -15,7 +15,7 @@ getUserMedia is handled as optional</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that setting an optional constraint in getUserMedia is handled as optional", {timeout:10000});
+var t = async_test("Tests that setting an optional constraint in getUserMedia is handled as optional");
 t.step(function() {
   navigator.mediaDevices.getUserMedia({video: {advanced: [{width: {min:1024, max: 800}}]}})
     .then(t.step_func(function (stream) {
index 283bcb2..ad37765 100644 (file)
@@ -15,7 +15,7 @@ constraint (width &gt;=0) in getUserMedia works</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that setting a trivial mandatory constraint in getUserMedia works", {timeout:10000});
+var t = async_test("Tests that setting a trivial mandatory constraint in getUserMedia works");
 t.step(function() {
   navigator.mediaDevices.getUserMedia({video: {width: {min:0}}})
     .then(t.step_func(function (stream) {
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/META.yml b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/META.yml
new file mode 100644 (file)
index 0000000..960dc3a
--- /dev/null
@@ -0,0 +1,6 @@
+spec: https://w3c.github.io/mediacapture-main/
+suggested_reviewers:
+  - agouaillard
+  - alvestrand
+  - youennf
+  - jan-ivar
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all-expected.txt
deleted file mode 100644 (file)
index 351e345..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Description
-
-This test checks for the presence of the navigator.mediaDevices.getUserMedia method.
-
-
-FAIL idl_test setup promise_test: Unhandled rejection with value: object "WebIDLParseError: Syntax error at line 147, since `interface NavigatorUserMedia`:
-Navigator implements NavigatorUserMedia;
-^ Unrecognised tokens"
-
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html
deleted file mode 100644 (file)
index f728641..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<!doctype html>
-<html>
-  <head>
-    <title>getUserMedia: Non-Interactive test for mediaDevices APIs</title>
-    <link rel="author" title="Dr Alex Gouaillard" href="mailto:agouaillard@gmail.com"/>
-    <link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#mediadevices">
-    <link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#mediadevices-interface-extensions">
-    <meta name='assert' content='Check the mediaDevices APIs.'/>
-  </head>
-  <body>
-    <h1 class="instructions">Description</h1>
-    <p class="instructions">This test checks for the presence of the
-    <code>navigator.mediaDevices.getUserMedia</code> method.</p>
-    <div id='log'></div>
-    <script src=/resources/testharness.js></script>
-    <script src=/resources/testharnessreport.js></script>
-    <script src=/resources/WebIDLParser.js></script>
-    <script src=/resources/idlharness.js></script>
-    <script>
-      'use strict';
-
-      idl_test(
-        ['mediacapture-main'],
-        ['dom', 'html'],
-        idl_array => {
-          idl_array.add_objects({
-            "Navigator": ["navigator"],
-            "MediaDevices": ["navigator.mediaDevices"],
-          });
-        }
-      );
-    </script>
-  </body>
-</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices-expected.txt
deleted file mode 100644 (file)
index f4e12b2..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-Description
-
-This test checks for the presence of the navigator.mediaDevices.enumerateDevices() method.
-
-
-FAIL idl_test setup promise_test: Unhandled rejection with value: object "WebIDLParseError: Syntax error at line 147, since `interface NavigatorUserMedia`:
-Navigator implements NavigatorUserMedia;
-^ Unrecognised tokens"
-
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
deleted file mode 100644 (file)
index e05c8d5..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<!doctype html>
-<html>
-<head>
-<title>enumerateDevices: test that enumerateDevices is present</title>
-<link rel="author" title="Dr Alex Gouaillard" href="mailto:agouaillard@gmail.com"/>
-<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#methods-2">
-<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#device-info">
-<link rel="help" href="http://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaDeviceKind">
-<meta name='assert' content='Check that the enumerateDevices() method is present.'/>
-</head>
-<body>
-<h1 class="instructions">Description</h1>
-<p class="instructions">This test checks for the presence of the
-<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
-<div id='log'></div>
-<script src=/resources/testharness.js></script>
-<script src=/resources/testharnessreport.js></script>
-<script src=/resources/WebIDLParser.js></script>
-<script src=/resources/idlharness.js></script>
-<script>
-  "use strict";
-  idl_test(
-    ['mediacapture-main'],
-    ['dom', 'html'],
-    async idl_array => {
-      assert_true(undefined !== navigator.mediaDevices.enumerateDevices,
-        "navigator.mediaDevices.enumerateDevices exists");
-
-      const list = await navigator.mediaDevices.enumerateDevices();
-      if( list.length > 0 ) {
-        window._mediaInfo = list[0];
-        idl_array.add_objects({MediaDeviceInfo: ["_mediaInfo"]});
-      }
-
-      for(const media of list) {
-        if( media.kind == "audioinput" ||
-            media.kind == "videoinput") {
-          // TODO -- Check InputDeviceInfo IDL, getCapabilities()
-        } else if ( media.kind == "audiooutput" ) {
-          // TODO -- pass
-        } else {
-          assert_unreached("media.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
-        }
-      }
-    }
-  );
-</script>
-</body>
-</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext-expected.txt
new file mode 100644 (file)
index 0000000..7064557
--- /dev/null
@@ -0,0 +1,3 @@
+
+FAIL MediaDevices and SecureContext assert_false: This test must be run in a non secure context expected false got true
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext.html
new file mode 100644 (file)
index 0000000..bada628
--- /dev/null
@@ -0,0 +1,19 @@
+<!doctype html>
+<html>
+<head>
+<title>MediaDevices and SecureContext</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+test(function() {
+  assert_false(window.isSecureContext, "This test must be run in a non secure context");
+  assert_false('MediaDevices' in window, "MediaDevices is not exposed");
+  assert_false('MediaDeviceInfo' in window, "MediaDeviceInfo is not exposed");
+  assert_false('getUserMedia' in navigator, "getUserMedia is not exposed");
+  assert_false('mediaDevices' in navigator, "mediaDevices is not exposed");
+});
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https-expected.txt
new file mode 100644 (file)
index 0000000..ecbf0b9
--- /dev/null
@@ -0,0 +1,7 @@
+Description
+
+This test checks for the presence of camera in navigator.mediaDevices.enumerateDevices() method.
+
+
+FAIL Camera is not exposed in mediaDevices.enumerateDevices() assert_in_array: value "videoinput" not in array ["audioinput", "audiooutput"]
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html
new file mode 100644 (file)
index 0000000..1bb086d
--- /dev/null
@@ -0,0 +1,30 @@
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices: test enumerateDevices should not expose camera devices if they are not allowed to use</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices">
+<meta name='assert' content='Check that the enumerateDevices() method should not exposed camera devices.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of camera in
+<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
+<div id='log'></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+"use strict";
+promise_test(async () => {
+  assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
+  const deviceList =  await navigator.mediaDevices.enumerateDevices();
+  for (const mediaInfo of deviceList) {
+    assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
+    assert_not_equals(mediaInfo.kind, undefined,     "mediaInfo's kind     should exist.");
+    assert_not_equals(mediaInfo.label, undefined,    "mediaInfo's label    should exist.");
+    assert_not_equals(mediaInfo.groupId, undefined,  "mediaInfo's groupId  should exist.");
+    assert_in_array(mediaInfo.kind, ["audioinput", "audiooutput"]);
+  }
+}, "Camera is not exposed in mediaDevices.enumerateDevices()");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html.headers b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html.headers
new file mode 100644 (file)
index 0000000..2adc5e2
--- /dev/null
@@ -0,0 +1 @@
+Feature-Policy: camera 'none'
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https-expected.txt
new file mode 100644 (file)
index 0000000..a250f5e
--- /dev/null
@@ -0,0 +1,7 @@
+Description
+
+This test checks for the presence of microphone in navigator.mediaDevices.enumerateDevices() method.
+
+
+FAIL Microphone is not exposed in mediaDevices.enumerateDevices() assert_in_array: value "audioinput" not in array ["videoinput", "audiooutput"]
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html
new file mode 100644 (file)
index 0000000..8d535ce
--- /dev/null
@@ -0,0 +1,30 @@
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices: test enumerateDevices should not expose microphone devices if they are not allowed to use</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices">
+<meta name='assert' content='Check that the enumerateDevices() method should not exposed microphone devices.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of microphone in
+<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
+<div id='log'></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+"use strict";
+promise_test(async () => {
+  assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
+  const deviceList =  await navigator.mediaDevices.enumerateDevices();
+  for (const mediaInfo of deviceList) {
+    assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
+    assert_not_equals(mediaInfo.kind, undefined,     "mediaInfo's kind     should exist.");
+    assert_not_equals(mediaInfo.label, undefined,    "mediaInfo's label    should exist.");
+    assert_not_equals(mediaInfo.groupId, undefined,  "mediaInfo's groupId  should exist.");
+    assert_in_array(mediaInfo.kind, ["videoinput", "audiooutput"]);
+  }
+}, "Microphone is not exposed in mediaDevices.enumerateDevices()");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html.headers b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html.headers
new file mode 100644 (file)
index 0000000..a86e0a0
--- /dev/null
@@ -0,0 +1 @@
+Feature-Policy: microphone 'none'
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https-expected.txt
new file mode 100644 (file)
index 0000000..e9b1087
--- /dev/null
@@ -0,0 +1,4 @@
+
+FAIL enumerateDevices returns new objects in case device-info permission is not granted assert_not_equals: got disallowed value object "[object MediaDeviceInfo]"
+FAIL enumerateDevices returns new objects in case device-info permission is granted assert_not_equals: got disallowed value object "[object MediaDeviceInfo]"
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html
new file mode 100644 (file)
index 0000000..177beb6
--- /dev/null
@@ -0,0 +1,34 @@
+<!doctype html>
+<html>
+<head>
+<title>enumerateDevices is returning new MediaDeviceInfo objects every time</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+function doTest(callGetUserMedia, testName)
+{
+    promise_test(async () => {
+        if (callGetUserMedia)
+            await navigator.mediaDevices.getUserMedia({audio : true, video: true});
+
+        const deviceList1 =  await navigator.mediaDevices.enumerateDevices();
+        const deviceList2 =  await navigator.mediaDevices.enumerateDevices();
+
+        assert_equals(deviceList1.length, deviceList2.length);
+        for (let i = 0; i < deviceList1.length; i++) {
+            const device1 = deviceList1[i];
+            const device2 = deviceList2[i];
+            assert_not_equals(device1, device2);
+            assert_equals(device1.deviceId, device2.deviceId, "deviceId");
+            assert_equals(device1.kind, device2.kind, "kind");
+        }
+    }, testName);
+}
+
+doTest(false, "enumerateDevices returns new objects in case device-info permission is not granted");
+doTest(true, "enumerateDevices returns new objects in case device-info permission is granted");
+</script>
+</body>
+</html>
index d6ecd6b..9f97ff6 100644 (file)
@@ -3,5 +3,6 @@ Description
 This test checks for the presence of the navigator.mediaDevices.enumerateDevices() method.
 
 
-PASS mediaDevices.enumerateDevices() is present and working on navigator 
+PASS mediaDevices.enumerateDevices() is present and working 
+FAIL InputDeviceInfo is supported promise_test: Unhandled rejection with value: object "ReferenceError: Can't find variable: InputDeviceInfo"
 
index 806416e..efb4607 100644 (file)
 <script>
 "use strict";
 //NOTE ALEX: for completion, a test for ondevicechange event is missing.
-test(function () {
-  assert_true(undefined !== navigator.mediaDevices.enumerateDevices, "navigator.mediaDevices.enumerateDevices exists");
-  var p = navigator.mediaDevices.enumerateDevices()
-  p.then(function(list){
-    for(let mediainfo of list){
-      // TODO check the type of mediainfo
-      assert_true(undefined !== mediainfo.deviceId, "mediaInfo's deviceId should exist.");
-      assert_true(undefined !== mediainfo.kind,     "mediaInfo's kind     should exist.");
-      assert_true(undefined !== mediainfo.label,    "mediaInfo's label    should exist.");
-      assert_true(undefined !== mediainfo.groupId,  "mediaInfo's groupId  should exist.");
-      // TODO the values of some of those fields should be empty string by default if no permission has been requested.
-      if( mediainfo.kind == "audioinput" ||
-          mediainfo.kind == "videoinput") {
-        // NOTE ALEX: looks like nobody has implemented that. How can I make it a separate test,
-        // ...        to have better granularity?
-        // assert_true(undefined !== mediainfo.getCapabilities(), "MediaDeviceInfo.getCapabilities() exists.");
-        // var cap = mediainfo.getcapabilities();
-      } else if ( mediainfo.kind !== "audiooutput" ) {
-        assert_unreached("mediainfo.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
-      }
+promise_test(async () => {
+  assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
+  const deviceList =  await navigator.mediaDevices.enumerateDevices();
+  for (const mediaInfo of deviceList) {
+    assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
+    assert_not_equals(mediaInfo.kind, undefined,     "mediaInfo's kind     should exist.");
+    assert_not_equals(mediaInfo.label, undefined,    "mediaInfo's label    should exist.");
+    assert_not_equals(mediaInfo.groupId, undefined,  "mediaInfo's groupId  should exist.");
+    assert_in_array(mediaInfo.kind, ["videoinput", "audioinput", "audiooutput"]);
+  }
+}, "mediaDevices.enumerateDevices() is present and working");
+
+promise_test(async () => {
+  const deviceList =  await navigator.mediaDevices.enumerateDevices();
+  for (const mediaInfo of deviceList) {
+    if (mediaInfo.kind == "audioinput" || mediaInfo.kind == "videoinput") {
+      assert_true(mediaInfo instanceof InputDeviceInfo);
+    } else if ( mediaInfo.kind == "audiooutput" ) {
+      assert_true(mediaInfo instanceof MediaDeviceInfo);
+    } else {
+      assert_unreached("mediaInfo.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
     }
-  })
-  p.catch(function(err){
-    assert_unreached("A call to enumerateDevices() should never fail.");
-  });
-}, "mediaDevices.enumerateDevices() is present and working on navigator");
+  }
+}, "InputDeviceInfo is supported");
 </script>
 </body>
 </html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https-expected.txt
new file mode 100644 (file)
index 0000000..bf30e8b
--- /dev/null
@@ -0,0 +1,22 @@
+Description
+
+This test checks for the presence of the navigator.mediaDevices.getSupportedConstraints() method.
+
+
+PASS navigator.mediaDevices.getSupportedConstraints exists 
+PASS width is supported 
+PASS height is supported 
+PASS aspectRatio is supported 
+PASS frameRate is supported 
+PASS facingMode is supported 
+FAIL resizeMode is supported assert_true: expected true got undefined
+FAIL sampleRate is supported assert_true: expected true got false
+FAIL sampleSize is supported assert_true: expected true got false
+FAIL echoCancellation is supported assert_true: expected true got false
+FAIL autoGainControl is supported assert_true: expected true got undefined
+FAIL noiseSuppression is supported assert_true: expected true got undefined
+FAIL latency is supported assert_true: expected true got undefined
+FAIL channelCount is supported assert_true: expected true got undefined
+PASS deviceId is supported 
+FAIL groupId is supported assert_true: expected true got false
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html
new file mode 100644 (file)
index 0000000..453184a
--- /dev/null
@@ -0,0 +1,48 @@
+<!doctype html>
+<html>
+<head>
+<title>Test navigator.mediaDevices.getSupportedConstraints()</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#enumerating-devices">
+<meta name='assert' content='Test the getSupportedConstraints() method.'/>
+</head>
+<body>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks for the presence of the
+<code>navigator.mediaDevices.getSupportedConstraints()</code> method.</p>
+<div id='log'></div>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+"use strict";
+test(() => {
+  assert_inherits(navigator.mediaDevices, "getSupportedConstraints");
+  assert_equals(typeof navigator.mediaDevices.getSupportedConstraints, "function");
+}, "navigator.mediaDevices.getSupportedConstraints exists");
+
+{
+  const properties = [
+    "width",
+    "height",
+    "aspectRatio",
+    "frameRate",
+    "facingMode",
+    "resizeMode",
+    "sampleRate",
+    "sampleSize",
+    "echoCancellation",
+    "autoGainControl",
+    "noiseSuppression",
+    "latency",
+    "channelCount",
+    "deviceId",
+    "groupId"];
+  properties.forEach(property => {
+    test(()=>{
+      const supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
+      assert_true(supportedConstraints[property]);
+    }, property + " is supported");
+  });
+}
+</script>
+</body>
+</html>
index aa7f782..00fbb82 100644 (file)
@@ -4,4 +4,9 @@ This test checks for the presence of the navigator.mediaDevices.getUserMedia met
 
 
 PASS mediaDevices.getUserMedia() is present on navigator 
+FAIL groupId is correctly supported by getUserMedia() for video devices assert_true: groupId should be supported expected true got false
+FAIL groupId is correctly supported by getUserMedia() for audio devices assert_true: groupId should be supported expected true got false
+FAIL getUserMedia() supports setting none as resizeMode. assert_true: resizeMode should be supported expected true got undefined
+FAIL getUserMedia() supports setting crop-and-scale as resizeMode. assert_true: resizeMode should be supported expected true got undefined
+FAIL getUserMedia() fails with exact invalid resizeMode. assert_true: resizeMode should be supported expected true got undefined
 
index 0573ab0..693f3bd 100644 (file)
@@ -36,6 +36,86 @@ test(function () {
   //   list.deviceId
   //   list.groupId
   }, "mediaDevices.getUserMedia() is present on navigator");
+
+promise_test(async t => {
+  assert_true(navigator.mediaDevices.getSupportedConstraints()["groupId"],
+    "groupId should be supported");
+  const devices = await navigator.mediaDevices.enumerateDevices();
+  for (const device of devices) {
+    await navigator.mediaDevices.getUserMedia(
+        {video: {groupId: {exact: device.groupId}}}).then(stream => {
+      const found_device = devices.find(({deviceId}) =>
+        deviceId == stream.getTracks()[0].getSettings().deviceId);
+      assert_not_equals(found_device, undefined);
+      assert_equals(found_device.kind, "videoinput");
+      assert_equals(found_device.groupId, device.groupId);
+      stream.getTracks().forEach(t => t.stop());
+    }, error => {
+      assert_equals(error.name, "OverconstrainedError");
+      assert_equals(error.constraint, "groupId");
+      const found_device = devices.find(element =>
+        element.kind == "videoinput" && element.groupId == device.groupId);
+      assert_equals(found_device, undefined);
+    });
+  }
+}, 'groupId is correctly supported by getUserMedia() for video devices');
+
+promise_test(async t => {
+  assert_true(navigator.mediaDevices.getSupportedConstraints()["groupId"],
+    "groupId should be supported");
+  const devices = await navigator.mediaDevices.enumerateDevices();
+  for (const device of devices) {
+    await navigator.mediaDevices.getUserMedia(
+        {audio: {groupId: {exact: device.groupId}}}).then(stream => {
+      const found_device = devices.find(({deviceId}) =>
+        deviceId == stream.getTracks()[0].getSettings().deviceId);
+      assert_not_equals(found_device, undefined);
+      assert_equals(found_device.kind, "audioinput");
+      assert_equals(found_device.groupId, device.groupId);
+      stream.getTracks().forEach(t => t.stop());
+    }, error => {
+      assert_equals(error.name, "OverconstrainedError");
+      assert_equals(error.constraint, "groupId");
+      const found_device = devices.find(element =>
+        element.kind == "audioinput" && element.groupId == device.groupId);
+      assert_equals(found_device, undefined);
+    });
+  }
+}, 'groupId is correctly supported by getUserMedia() for audio devices');
+
+promise_test(async t => {
+  assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+    "resizeMode should be supported");
+  const stream = await navigator.mediaDevices.getUserMedia(
+      { video: {resizeMode: {exact: 'none'}}});
+  const [track] = stream.getVideoTracks();
+  t.add_cleanup(() => track.stop());
+  assert_equals(track.getSettings().resizeMode, 'none');
+}, 'getUserMedia() supports setting none as resizeMode.');
+
+promise_test(async t => {
+  assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+    "resizeMode should be supported");
+  const stream = await navigator.mediaDevices.getUserMedia(
+      { video: {resizeMode: {exact: 'crop-and-scale'}}});
+  const [track] = stream.getVideoTracks();
+  t.add_cleanup(() => track.stop());
+  assert_equals(track.getSettings().resizeMode, 'crop-and-scale');
+}, 'getUserMedia() supports setting crop-and-scale as resizeMode.');
+
+promise_test(async t => {
+  assert_true(navigator.mediaDevices.getSupportedConstraints()["resizeMode"],
+    "resizeMode should be supported");
+  try {
+    const stream = await navigator.mediaDevices.getUserMedia(
+        { video: {resizeMode: {exact: 'INVALID'}}});
+    t.add_cleanup(() => stream.getVideoTracks()[0].stop());
+    t.unreached_func('getUserMedia() should fail with invalid resizeMode')();
+  } catch (e) {
+    assert_equals(e.name, 'OverconstrainedError');
+    assert_equals(e.constraint, 'resizeMode');
+  }
+}, 'getUserMedia() fails with exact invalid resizeMode.');
 </script>
 </body>
 </html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https-expected.txt
new file mode 100644 (file)
index 0000000..9b2bc2b
--- /dev/null
@@ -0,0 +1,11 @@
+When prompted, accept to share your video stream.
+
+Description
+
+This test checks that a HTMLMediaElement with an assigned MediaStream with a video track fires the appropriate events to reach the "canplay" event and readyState HAVE_ENOUGH_DATA even when not playing or autoplaying.
+
+
+
+PASS Tests that loading a MediaStream in a media element eventually results in "canplay" even when not playing or autoplaying 
+PASS Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html
new file mode 100644 (file)
index 0000000..714ae01
--- /dev/null
@@ -0,0 +1,102 @@
+<!doctype html>
+<html>
+<head>
+<title>Assigning a MediaStream to a media element and not playing it results in rendering a first frame</title>
+</head>
+<body>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that a HTMLMediaElement with an
+assigned MediaStream with a video track fires the appropriate events to reach
+the "canplay" event and readyState HAVE_ENOUGH_DATA even when not playing or
+autoplaying.</p>
+<video id="vid"></video>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+'use strict';
+const vid = document.getElementById("vid");
+
+promise_test(async t => {
+  const wait = ms => new Promise(r => t.step_timeout(r, ms));
+  const timeout = (promise, time, msg) => Promise.race([
+    promise,
+    wait(time).then(() => Promise.reject(new Error(msg)))
+  ]);
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+  vid.srcObject = stream;
+
+  await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplay\"");
+}, "Tests that loading a MediaStream in a media element eventually results in \"canplay\" even when not playing or autoplaying");
+
+promise_test(async t => {
+  const wait = ms => new Promise(r => t.step_timeout(r, ms));
+  const timeout = (promise, time, msg) => Promise.race([
+    promise,
+    wait(time).then(() => Promise.reject(new Error(msg)))
+  ]);
+  const unexpected = e => assert_unreached(`Got unexpected event ${e.type}`);
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.ondurationchange = null;
+    stream.getTracks().forEach(track => track.stop())
+  });
+  vid.srcObject = stream;
+
+  vid.onloadstart = unexpected;
+  vid.ondurationchange = unexpected;
+  vid.onresize = unexpected;
+  vid.onloadedmetadata = unexpected;
+  vid.onloadeddata = unexpected;
+  vid.oncanplay = unexpected;
+  vid.oncanplaythrough = unexpected;
+
+  await timeout(new Promise(r => vid.onloadstart = r), 8000,
+    "loadstart timeout");
+  vid.onloadstart = unexpected;
+
+  await timeout(new Promise(r => vid.ondurationchange = r), 8000,
+    "durationchange timeout");
+  vid.ondurationchange = unexpected;
+  assert_equals(vid.duration, Infinity, "duration changes to Infinity");
+
+  await timeout(new Promise(r => vid.onresize = r), 8000,
+    "resize timeout");
+  vid.onresize = unexpected;
+  assert_not_equals(vid.videoWidth, 0,
+    "videoWidth is something after \"resize\"");
+  assert_not_equals(vid.videoHeight, 0,
+    "videoHeight is something after \"resize\"");
+
+  await timeout(new Promise(r => vid.onloadedmetadata = r), 8000,
+    "loadedmetadata timeout");
+  vid.onloadedmetadata = unexpected;
+  assert_greater_than_equal(vid.readyState, vid.HAVE_METADATA,
+    "readyState is at least HAVE_METADATA after \"loadedmetadata\"");
+
+  await timeout(new Promise(r => vid.onloadeddata = r), 8000,
+    "loadeddata timeout");
+  vid.onloadeddata = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"loadeddata\" since there's no buffering");
+
+  await timeout(new Promise(r => vid.oncanplay = r), 8000, "canplay timeout");
+  vid.oncanplay = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplay\" since there's no buffering");
+
+  await timeout(new Promise(r => vid.oncanplaythrough = r), 8000,
+    "canplaythrough timeout");
+  vid.oncanplaythrough = unexpected;
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "readyState is HAVE_ENOUGH_DATA after \"canplaythrough\"");
+
+  // Crank the event loop to see whether any more events are fired.
+  await wait(100);
+}, "Tests that loading a MediaStream in a media element sees all the expected (deterministic) events even when not playing or autoplaying");
+</script>
+</body>
+</html>
@@ -1,12 +1,8 @@
->
 When prompted, accept to share your audio and video streams.
 
-Description
-
 This test checks that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.
 
 
-
-FAIL Test that preload 'none' is ignored for MediaStream object URL used as src Type error
-FAIL Test that preload 'none' is ignored for MediaStream used as srcObject assert_unreached: 'suspend' should not be fired. Reached unreachable code
+FAIL Test that preload 'none' is ignored for MediaStream object URL used as srcObject for audio assert_unreached: 'suspend' should not be fired. Reached unreachable code
+FAIL Test that preload 'none' is ignored for MediaStream used as srcObject for video assert_unreached: 'suspend' should not be fired. Reached unreachable code
 
@@ -1,16 +1,15 @@
 <!DOCTYPE html>
-<!-- Copyright © 2016 Chromium authors and World Wide Web Consortium, (Massachusetts Institute of Technology, ERCIM, Keio University, Beihang). -->
 <html>
     <head>
-        <title>Test that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.</title>>
+        <title>Test that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.</title>
         <link rel="author" title="Matthew Wolenetz" href="mailto:wolenetz@chromium.org"/>
         <script src="/resources/testharness.js"></script>
         <script src="/resources/testharnessreport.js"></script>
     </head>
     <body>
         <p class="instructions">When prompted, accept to share your audio and video streams.</p>
-        <h1 class="instructions">Description</h1>
         <p class="instructions">This test checks that the HTMLMediaElement preload 'none' attribute value is ignored for MediaStream used as srcObject and MediaStream object URLs used as src.</p>
+        <div id=log></div>
 
         <audio preload="none"></audio>
         <video preload="none"></video>
                 navigator.mediaDevices.getUserMedia({audio:true})
                   .then(t.step_func(function(stream)
                   {
-                      testPreloadNone(t, aud, t.step_func(function()
-                      {
-                          aud.src = URL.createObjectURL(stream);
-                          t.add_cleanup(function() { URL.revokeObjectURL(aud.src); });
-                      }));
+                      testPreloadNone(t, aud, t.step_func(function() { aud.srcObject = stream; }));
                   }),
                   t.unreached_func("getUserMedia error callback was invoked."));
-            }, "Test that preload 'none' is ignored for MediaStream object URL used as src");
+            }, "Test that preload 'none' is ignored for MediaStream object URL used as srcObject for audio");
 
             async_test(function(t)
             {
@@ -57,7 +52,7 @@
                   {
                       testPreloadNone(t, vid, t.step_func(function() { vid.srcObject = stream; }));
                   }), t.unreached_func("getUserMedia error callback was invoked."));
-            }, "Test that preload 'none' is ignored for MediaStream used as srcObject");
+            }, "Test that preload 'none' is ignored for MediaStream used as srcObject for video");
         </script>
     </body>
 </html>
index 812fefd..293f7c2 100644 (file)
@@ -6,5 +6,22 @@ This test checks that the MediaStream object returned by the success callback in
 
 
 
+Harness Error (TIMEOUT), message = null
+
 PASS Tests that a MediaStream can be assigned to a video element with srcObject 
+PASS Tests that a MediaStream assigned to a video element is not seekable 
+PASS Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially 
+TIMEOUT Tests that a MediaStream assigned to a video element has expected duration Test timed out
+NOTRUN Tests that a video element with a MediaStream assigned is not preloaded 
+NOTRUN Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical) 
+NOTRUN Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different) 
+NOTRUN Tests that a media element with an assigned MediaStream reports the played attribute as expected 
+NOTRUN Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected 
+NOTRUN Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created 
+NOTRUN Tests that a media element with an assigned MediaStream does not advance currentTime while paused 
+NOTRUN Tests that the loop attribute has no effect on a media element with an assigned MediaStream 
+NOTRUN Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through tracks ending 
+NOTRUN Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through audio tracks ending 
+NOTRUN Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through track removal 
+NOTRUN Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through track removal 
 
index 2ed96ec..790f73a 100644 (file)
 the success callback in getUserMedia can be properly assigned to a video element
 via the <code>srcObject</code> attribute.</p>
 
+<audio id="aud"></audio>
 <video id="vid"></video>
 
 <div id='log'></div>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var vid = document.getElementById("vid");
-var t = async_test("Tests that a MediaStream can be assigned to a video element with srcObject", {timeout: 10000});
-t.step(function() {
-  navigator.mediaDevices.getUserMedia({video: true})
-    .then(t.step_func(function (stream) {
-      var testOncePlaying = function() {
-         assert_equals(vid.played.length, 1, "A MediaStream's timeline always consists of a single range");
-         assert_equals(vid.played.start(0), 0, "A MediaStream's timeline always consists of a single range");
-         assert_approx_equals(vid.played.end(0), vid.currentTime, 0.0001, "A MediaStream's timeline always consists of a single range");
-         assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA, "Upon selecting a media stream, the UA sets readyState to HAVE_ENOUGH_DATA");
-         assert_equals(vid.duration, Infinity, " A MediaStream does not have a pre-defined duration. ");
-         var time = vid.currentTime;
-
-         assert_approx_equals(vid.currentTime, time, 0.0001, "The UA MUST ignore attempts to set the currentTime attribute");
-         // TODO add test that duration must be set to currentTime
-         // when mediastream is destroyed
-         vid.removeEventListener("timeupdate", testOncePlaying, false);
-         t.done();
-      }
-      vid.addEventListener("timeupdate", t.step_func(testOncePlaying), false);
-      vid.srcObject = stream;
-      vid.play();
-      assert_true(!vid.seeking, "A MediaStream is not seekable");
-      assert_equals(vid.seekable.length, 0, "A MediaStream is not seekable");
-      assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
-      assert_equals(vid.playbackRate, 1, "playback rate is always 1");
-      assert_equals(vid.buffered.length, 0, "A MediaStream cannot be preloaded.  Therefore, there is no buffered timeranges");
-      assert_equals(vid.duration, vid.readyState == vid.HAVE_NOTHING ? NaN : Infinity, " A MediaStream does not have a pre-defined duration. ");
-    }), function(error) {});
-});
+'use strict';
+const vid = document.getElementById("vid");
+
+function queueTask(f) {
+  window.onmessage = f;
+  window.postMessage("hi");
+}
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+}, "Tests that a MediaStream can be assigned to a video element with srcObject");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_true(!vid.seeking, "A MediaStream is not seekable");
+  assert_equals(vid.seekable.length, 0, "A MediaStream is not seekable");
+}, "Tests that a MediaStream assigned to a video element is not seekable");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_equals(vid.readyState, vid.HAVE_NOTHING,
+    "readyState is HAVE_NOTHING initially");
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.readyState, vid.HAVE_ENOUGH_DATA,
+    "Upon having loaded a media stream, the UA sets readyState to HAVE_ENOUGH_DATA");
+}, "Tests that a MediaStream assigned to a video element is in readyState HAVE_NOTHING initially");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_equals(vid.duration, NaN,
+    "A MediaStream does not have any duration initially.");
+  await new Promise(r => vid.ondurationchange = r);
+  assert_equals(vid.duration, Infinity,
+    "A loaded MediaStream does not have a pre-defined duration.");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  for (const t of stream.getTracks()) {
+    t.stop();
+  }
+
+  await new Promise(r => vid.ondurationchange = r);
+  assert_equals(vid.duration, vid.currentTime,
+    "After ending playback, duration gets set to currentTime");
+}, "Tests that a MediaStream assigned to a video element has expected duration");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.preload = "metadata";
+  vid.srcObject = stream;
+
+  assert_equals(vid.buffered.length, 0,
+    "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+  assert_equals(vid.preload, "none", "preload must always be none");
+  vid.preload = "auto";
+  assert_equals(vid.preload, "none", "Setting preload must be ignored");
+
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.buffered.length, 0,
+    "A MediaStream cannot be preloaded. Therefore, there are no buffered timeranges");
+
+  vid.srcObject = null;
+
+  assert_equals(vid.preload, "metadata",
+    "The preload attribute returns the value it had before using a MediaStream");
+}, "Tests that a video element with a MediaStream assigned is not preloaded");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.defaultPlaybackRate = 0.3;
+  vid.playbackRate = 0.3;
+  vid.onratechange = t.unreached_func("ratechange event must not be fired");
+  vid.srcObject = stream;
+
+  assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
+  vid.defaultPlaybackRate = 0.5;
+  assert_equals(vid.defaultPlaybackRate, 1,
+    "Setting defaultPlaybackRate must be ignored");
+
+  assert_equals(vid.playbackRate, 1, "playback rate is always 1");
+  vid.playbackRate = 0.5;
+  assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
+
+  vid.srcObject = null;
+  assert_equals(vid.defaultPlaybackRate, 0.3,
+    "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+  assert_equals(vid.playbackRate, 0.3,
+    "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject");
+
+  // Check that there's no ratechange event
+  await new Promise(r => t.step_timeout(r, 100));
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is identical)");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+
+  vid.defaultPlaybackRate = 0.3;
+  vid.playbackRate = 0.4;
+  vid.onratechange = t.unreached_func("ratechange event must not be fired");
+  vid.srcObject = stream;
+
+  assert_equals(vid.defaultPlaybackRate, 1, "playback rate is always 1");
+  vid.defaultPlaybackRate = 0.5;
+  assert_equals(vid.defaultPlaybackRate, 1,
+    "Setting defaultPlaybackRate must be ignored");
+
+  assert_equals(vid.playbackRate, 1, "playback rate is always 1");
+  vid.playbackRate = 0.5;
+  assert_equals(vid.playbackRate, 1, "Setting playbackRate must be ignored");
+
+  vid.srcObject = null;
+  assert_equals(vid.defaultPlaybackRate, 0.3,
+    "The defaultPlaybackRate attribute returns the value it had before using a MediaStream");
+  assert_equals(vid.playbackRate, 0.3,
+    "The playbackRate attribute is set to the value of the defaultPlaybackRate attribute when unsetting srcObject (and fires ratechange)");
+  await new Promise(r => vid.onratechange = r);
+}, "Tests that a video element with a MediaStream assigned ignores playbackRate attributes (defaultPlaybackRate is different)");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+  await new Promise(r => vid.oncanplay = r);
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_greater_than(vid.currentTime, 0,
+    "currentTime is greater than 0 after first timeupdate");
+
+  assert_equals(vid.played.length, 1,
+    "A MediaStream's timeline always consists of a single range");
+  assert_equals(vid.played.start(0), 0,
+    "A MediaStream's timeline always starts at zero");
+  assert_equals(vid.played.end(0), vid.currentTime,
+    "A MediaStream's end MUST return the last known currentTime");
+
+  const time = vid.currentTime;
+  vid.currentTime = 0;
+  assert_equals(vid.currentTime, time,
+    "The UA MUST ignore attempts to set the currentTime attribute");
+}, "Tests that a media element with an assigned MediaStream reports the played attribute as expected");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  assert_equals(vid.currentTime, 0, "The initial value is 0");
+  vid.currentTime = 42;
+  assert_equals(vid.currentTime, 0,
+    "The UA MUST ignore attempts to set the currentTime attribute (default playback start position)");
+
+  await new Promise(r => vid.onloadeddata = r);
+  assert_equals(vid.currentTime, 0, "The initial value is 0");
+  vid.currentTime = 42;
+  assert_equals(vid.currentTime, 0,
+    "The UA MUST ignore attempts to set the currentTime attribute (official playback position)");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_greater_than(vid.currentTime, 0,
+    "currentTime is greater than 0 after first timeupdate");
+
+  const lastTime = vid.currentTime;
+  vid.currentTime = 0;
+  assert_equals(vid.currentTime, lastTime,
+    "The UA MUST ignore attempts to set the currentTime attribute (restart)");
+
+  for(const t of stream.getTracks()) {
+    t.stop();
+  }
+  await new Promise(r => vid.onended = r);
+  assert_greater_than_equal(vid.currentTime, lastTime,
+    "currentTime advanced after stopping");
+}, "Tests that a media element with an assigned MediaStream reports the currentTime attribute as expected");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  await new Promise(r => t.step_timeout(r, 500));
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_between_exclusive(vid.currentTime, 0, 0.5,
+    "currentTime starts at 0 and has progressed at first timeupdate");
+}, "Tests that a media element with an assigned MediaStream starts its timeline at 0 regardless of when the MediaStream was created");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  vid.srcObject = stream;
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+
+  vid.pause();
+  const pauseCurrentTime = vid.currentTime;
+
+  await new Promise(r => vid.onpause = r);
+  vid.ontimeupdate = () => assert_unreached("No timeupdate while paused");
+
+  await new Promise(r => t.step_timeout(r, 500));
+  assert_equals(vid.currentTime, pauseCurrentTime,
+    "currentTime does not change while paused");
+
+  vid.play();
+
+  await new Promise(r => vid.ontimeupdate = r);
+  assert_between_exclusive(vid.currentTime - pauseCurrentTime, 0, 0.5,
+    "currentTime does not skip ahead after pause");
+}, "Tests that a media element with an assigned MediaStream does not advance currentTime while paused");
+
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => {
+    vid.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  assert_equals(vid.loop, false, "loop is false by default");
+  vid.srcObject = stream;
+
+  vid.loop = true;
+  assert_equals(vid.loop, true,
+    "loop can be changed when assigned a MediaStream");
+
+  await new Promise(r => vid.onloadeddata = r);
+  vid.loop = false;
+  assert_equals(vid.loop, false,
+    "loop can be changed when having loaded a MediaStream");
+
+  vid.play();
+  await new Promise(r => vid.ontimeupdate = r);
+  vid.loop = true;
+  assert_equals(vid.loop, true,
+    "loop can be changed when playing a MediaStream");
+
+  for(const t of stream.getTracks()) {
+    t.stop();
+  }
+  // If loop is ignored, we get "ended",
+  // otherwise the media element sets currentTime to 0 without ending.
+  await new Promise(r => vid.onended = r);
+}, "Tests that the loop attribute has no effect on a media element with an assigned MediaStream");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => { vid.srcObject = null; });
+  vid.srcObject = stream;
+
+  await vid.play();
+
+  for (const track of stream.getTracks()) {
+    track.stop();
+  }
+
+  assert_false(stream.active, "MediaStream becomes inactive with only ended tracks");
+  assert_false(vid.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (sync)");
+
+  await Promise.resolve();
+  assert_false(vid.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (microtask)");
+
+  let ended = false;
+  vid.onended = () => ended = true;
+  await new Promise(r => queueTask(r));
+
+  assert_true(vid.ended, "HTMLMediaElement becomes ended asynchronously when its MediaStream provider becomes inactive");
+  assert_true(ended, "HTMLMediaElement fires the ended event asynchronously when its MediaStream provider becomes inactive");
+}, "Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through tracks ending");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+  t.add_cleanup(() => {
+    aud.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  aud.srcObject = stream;
+
+  await aud.play();
+
+  for (const track of stream.getAudioTracks()) {
+    track.stop();
+  }
+
+  assert_true(stream.active, "MediaStream is still active with a live video track");
+  assert_false(aud.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (sync)");
+
+  await Promise.resolve();
+  assert_false(aud.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (microtask)");
+
+  let ended = false;
+  aud.onended = () => ended = true;
+  await new Promise(r => queueTask(r));
+
+  assert_true(aud.ended, "HTMLAudioElement becomes ended asynchronously when its MediaStream provider becomes inaudible");
+  assert_true(ended, "HTMLAudioElement fires the ended event asynchronously when its MediaStream provider becomes inaudible");
+}, "Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through audio tracks ending");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true});
+  t.add_cleanup(() => { vid.srcObject = null; });
+  vid.srcObject = stream;
+
+  await vid.play();
+
+  for (const track of stream.getTracks()) {
+    stream.removeTrack(track);
+  }
+
+  assert_false(stream.active, "MediaStream becomes inactive with no tracks");
+  assert_false(vid.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (sync)");
+
+  await Promise.resolve();
+  assert_false(vid.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (microtask)");
+
+  let ended = false;
+  vid.onended = () => ended = true;
+  await new Promise(r => queueTask(r));
+
+  assert_true(vid.ended, "HTMLMediaElement becomes ended asynchronously when its MediaStream provider becomes inactive");
+  assert_true(ended, "HTMLMediaElement fires the ended event asynchronously when its MediaStream provider becomes inactive");
+}, "Tests that a media element with an assigned MediaStream ends when the MediaStream becomes inactive through track removal");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+  t.add_cleanup(() => {
+    aud.srcObject = null;
+    stream.getTracks().forEach(track => track.stop());
+  });
+  aud.srcObject = stream;
+
+  await aud.play();
+
+  for (const track of stream.getAudioTracks()) {
+    stream.removeTrack(track);
+  }
+
+  assert_true(stream.active, "MediaStream is still active with a live video track");
+  assert_false(aud.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (sync)");
+
+  await Promise.resolve();
+  assert_false(aud.ended, "HTMLMediaElement reports ended the next time the event loop reaches step 1 (microtask)");
+
+  let ended = false;
+  aud.onended = () => ended = true;
+  await new Promise(r => queueTask(r));
+
+  assert_true(aud.ended, "HTMLAudioElement becomes ended asynchronously when its MediaStream provider becomes inaudible");
+  assert_true(ended, "HTMLAudioElement fires the ended event asynchronously when its MediaStream provider becomes inaudible");
+}, "Tests that an audio element with an assigned MediaStream ends when the MediaStream becomes inaudible through track removal");
 </script>
 </body>
 </html>
index e976b16..5423718 100644 (file)
@@ -15,7 +15,7 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that adding a track to a MediaStream works as expected", {timeout: 20000}); // longer timeout since requires double user interaction
+var t = async_test("Tests that adding a track to a MediaStream works as expected");
 t.step(function () {
   var audio, video;
 
index faa2c39..1ae0acd 100644 (file)
@@ -17,7 +17,7 @@ the success callback in getUserMedia has exactly one audio track.</p>
 <script src=/resources/testharnessreport.js></script>
 <script>
 var astream;
-var t = async_test("Tests that a MediaStream with exactly one audio track is returned", {timeout: 10000});
+var t = async_test("Tests that a MediaStream with exactly one audio track is returned");
 t.step(function() {
   navigator.mediaDevices.getUserMedia({audio:true}).then(t.step_func(function (stream) {
     astream = stream;
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https-expected.txt
new file mode 100644 (file)
index 0000000..0edcc02
--- /dev/null
@@ -0,0 +1,10 @@
+When prompted, accept to give permission to use your audio and video devices.
+
+Description
+
+This test checks that cloning MediaStreams and MediaStreamTracks works as expected.
+
+
+PASS Tests that cloning MediaStream objects works as expected 
+PASS Tests that cloning MediaStreamTrack objects works as expected 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https.html
new file mode 100644 (file)
index 0000000..1349188
--- /dev/null
@@ -0,0 +1,94 @@
+<!doctype html>
+<html>
+<head>
+<title>MediaStream and MediaStreamTrack clone()</title>
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediastream-clone">
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-clone">
+</head>
+<body>
+<p class="instructions">When prompted, accept to give permission to use your audio and video devices.</p>
+<h1 class="instructions">Description</h1>
+<p class="instructions">This test checks that cloning MediaStreams and MediaStreamTracks works as expected.</p>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+  assert_equals(stream.getAudioTracks().length, 1);
+  assert_equals(stream.getVideoTracks().length, 1);
+
+  const clone1 = stream.clone();
+  assert_equals(clone1.getAudioTracks().length, 1);
+  assert_equals(clone1.getVideoTracks().length, 1);
+  assert_not_equals(stream.getAudioTracks()[0].id, clone1.getAudioTracks()[0].id);
+  assert_not_equals(stream.getVideoTracks()[0].id, clone1.getVideoTracks()[0].id);
+
+  stream.getTracks().forEach(track => track.stop());
+  assert_false(stream.active);
+  assert_equals(stream.getAudioTracks()[0].readyState, "ended");
+  assert_equals(stream.getVideoTracks()[0].readyState, "ended");
+  assert_true(clone1.active);
+  assert_equals(clone1.getAudioTracks()[0].readyState, "live");
+  assert_equals(clone1.getVideoTracks()[0].readyState, "live");
+
+  clone1.getAudioTracks()[0].stop();
+  assert_true(clone1.active);
+  assert_equals(clone1.getAudioTracks()[0].readyState, "ended");
+  assert_equals(clone1.getVideoTracks()[0].readyState, "live");
+
+  const clone2 = clone1.clone();
+  assert_true(clone2.active);
+  assert_equals(clone2.getAudioTracks()[0].readyState, "ended");
+  assert_equals(clone2.getVideoTracks()[0].readyState, "live");
+
+  clone1.getVideoTracks()[0].stop();
+  clone2.getVideoTracks()[0].stop();
+
+  const clone3 = clone2.clone();
+  assert_false(clone3.active);
+  assert_equals(clone3.getAudioTracks()[0].readyState, "ended");
+  assert_equals(clone3.getVideoTracks()[0].readyState, "ended");
+  assert_not_equals(clone1.getAudioTracks()[0].id, clone2.getAudioTracks()[0].id);
+  assert_not_equals(clone1.getVideoTracks()[0].id, clone2.getVideoTracks()[0].id);
+  assert_not_equals(clone2.getAudioTracks()[0].id, clone3.getAudioTracks()[0].id);
+  assert_not_equals(clone2.getVideoTracks()[0].id, clone3.getVideoTracks()[0].id);
+  assert_not_equals(clone1.getAudioTracks()[0].id, clone3.getAudioTracks()[0].id);
+  assert_not_equals(clone1.getVideoTracks()[0].id, clone3.getVideoTracks()[0].id);
+}, "Tests that cloning MediaStream objects works as expected");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+  assert_equals(stream.getAudioTracks().length, 1);
+  assert_equals(stream.getVideoTracks().length, 1);
+  assert_equals(stream.getAudioTracks()[0].readyState, "live");
+  assert_equals(stream.getVideoTracks()[0].readyState, "live");
+  assert_true(stream.active);
+
+  const audio_clone = stream.getAudioTracks()[0].clone();
+  const video_clone = stream.getVideoTracks()[0].clone();
+  assert_equals(audio_clone.readyState, "live");
+  assert_equals(video_clone.readyState, "live");
+  assert_not_equals(stream.getAudioTracks()[0].id, audio_clone.id);
+  assert_not_equals(stream.getVideoTracks()[0].id, video_clone.id);
+
+  stream.getTracks().forEach(track => track.stop());
+  assert_false(stream.active);
+  assert_equals(stream.getAudioTracks()[0].readyState, "ended");
+  assert_equals(stream.getVideoTracks()[0].readyState, "ended");
+  assert_equals(audio_clone.readyState, "live");
+  assert_equals(video_clone.readyState, "live");
+
+  stream.addTrack(audio_clone);
+  stream.addTrack(video_clone);
+  assert_true(stream.active);
+
+  stream.getTracks().forEach(track => track.stop());
+  assert_false(stream.active);
+  assert_equals(audio_clone.readyState, "ended");
+  assert_equals(video_clone.readyState, "ended");
+}, "Tests that cloning MediaStreamTrack objects works as expected");
+
+</script>
+</body>
+</html>
index 3cc7066..48d0aaf 100644 (file)
@@ -1,22 +1,24 @@
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
-CONSOLE MESSAGE: line 16: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
+CONSOLE MESSAGE: line 13: Trying to call getUserMedia from a frame without correct 'allow' attribute.
 
 
 PASS Default "microphone" feature policy ["self"] allows the top-level document. 
 PASS Default "microphone" feature policy ["self"] allows same-origin iframes. 
 PASS Default "microphone" feature policy ["self"] disallows cross-origin iframes. 
-FAIL Feature policy "microphone" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: expected "#OK" but got "#NotAllowedError"
+PASS Feature policy "microphone" can be enabled in cross-origin iframes using "allow" attribute. 
 PASS Default "camera" feature policy ["self"] allows the top-level document. 
 PASS Default "camera" feature policy ["self"] allows same-origin iframes. 
 PASS Default "camera" feature policy ["self"] disallows cross-origin iframes. 
-FAIL Feature policy "camera" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: expected "#OK" but got "#NotAllowedError"
-PASS Default "camera; microphone" feature policy ["self"] allows the top-level document. 
-PASS Default "camera; microphone" feature policy ["self"] allows same-origin iframes. 
-PASS Default "camera; microphone" feature policy ["self"] disallows cross-origin iframes. 
-PASS Feature policy "camera; microphone" can be enabled in cross-origin iframes using "allow" attribute. 
+PASS Feature policy "camera" can be enabled in cross-origin iframes using "allow" attribute. 
+PASS Default "camera;microphone" feature policy ["self"] allows the top-level document. 
+PASS Default "camera;microphone" feature policy ["self"] allows same-origin iframes. 
+PASS Default "camera;microphone" feature policy ["self"] disallows cross-origin iframes. 
+FAIL Feature policy "camera;microphone" can be enabled in cross-origin iframes using "allow" attribute. assert_equals: expected "#OK" but got "#audio undefined and video true constraints must not be allowed."
 
index 21e3f5b..2e38b9e 100644 (file)
@@ -7,56 +7,73 @@
   <script>
   'use strict';
 
-  // The promise_factory must return a promise that runs the feature and
-  // resolves if feature usage is successful, otherwise rejects. Using
-  // getUserMedia is successful if at least one mic/camera is returned when
-  // mic/camera has been explicitly allowed by feature policy.
-  function promise_factory(allowed_features) {
-    return new Promise((resolve, reject) => {
-      navigator.mediaDevices.getUserMedia({video: true, audio: true}).then(
-          function(stream) {
-            // If microphone is allowed, there should be at least one microphone
-            // in the result. If camera is allowed, there should be at least one
-            // camera in the result.
-            if ((allowed_features.includes('microphone') &&
-                 stream.getAudioTracks().length == 0) ||
-                (allowed_features.includes('camera') &&
-                 stream.getVideoTracks().length == 0)) {
-                reject('Feature policy allowed feature but devices not ' +
-                    'present.');
-            } else {
-              // Otherwise the result is expected.
-              resolve();
-            }
-          },
-          function(error) { reject(error); });
-    });
-  };
+  async function gUM({audio, video}) {
+    let stream;
+    try {
+      stream = await navigator.mediaDevices.getUserMedia({audio, video});
+      // getUserMedia must guarantee the number of tracks requested or fail.
+      if ((audio && stream.getAudioTracks().length == 0) ||
+          (video && stream.getVideoTracks().length == 0)) {
+        throw {name: `All requested devices must be present with ` +
+                     `audio ${audio} and video ${video}, or fail`};
+      }
+    } finally {
+      if (stream) {
+        stream.getTracks().forEach(track => track.stop());
+      }
+    }
+  }
 
-  var cross_domain = get_host_info().HTTPS_REMOTE_ORIGIN;
+  async function must_disallow_gUM({audio, video}) {
+    try {
+      await gUM({audio, video});
+    } catch (e) {
+      if (e.name == 'NotAllowedError') {
+        return;
+      }
+      throw e;
+    }
+    throw {name: `audio ${audio} and video ${video} constraints must not be ` +
+                 `allowed.`};
+  }
+
+  const cross_domain = get_host_info().HTTPS_REMOTE_ORIGIN;
   run_all_fp_tests_allow_self(
-      cross_domain,
-      'microphone',
-      'NotAllowedError',
-      function() {
-        return promise_factory('microphone');
-      });
+    cross_domain,
+    'microphone',
+    'NotAllowedError',
+    async () => {
+      await gUM({audio: true});
+      if (window.location.href.includes(cross_domain)) {
+        await must_disallow_gUM({video: true});
+        await must_disallow_gUM({audio: true, video: true});
+      }
+    }
+  );
 
   run_all_fp_tests_allow_self(
-      cross_domain,
-      'camera',
-      'NotAllowedError',
-      function() {
-        return promise_factory('camera');
-      });
+    cross_domain,
+    'camera',
+    'NotAllowedError',
+    async () => {
+      await gUM({video: true});
+      if (window.location.href.includes(cross_domain)) {
+        await must_disallow_gUM({audio: true});
+        await must_disallow_gUM({audio: true, video: true});
+      }
+    }
+  );
 
   run_all_fp_tests_allow_self(
     cross_domain,
-    'camera; microphone',
+    'camera;microphone',
     'NotAllowedError',
-    function() {
-      return promise_factory('camera; microphone');
-    });
+    async () => {
+      await gUM({audio: true, video: true});
+      await gUM({audio: true});
+      await gUM({video: true});
+    }
+  );
   </script>
 </body>
 
index bfe561a..fd1a156 100644 (file)
@@ -17,7 +17,7 @@ MediaStream is allowed.</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that adding a track to an inactive MediaStream is allowed", {timeout:20000});
+var t = async_test("Tests that adding a track to an inactive MediaStream is allowed");
 t.step(function () {
   var audio, video;
 
index 8e282b6..8d96fe3 100644 (file)
@@ -14,7 +14,7 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that MediaStream.getTrackById works as expected", {timeout: 10000});
+var t = async_test("Tests that MediaStream.getTrackById works as expected");
 t.step(function () {
   navigator.mediaDevices.getUserMedia({video: true})
       .then(t.step_func(gotVideo), t.step_func(function (error) {
index 8e60709..b1e83f8 100644 (file)
@@ -20,34 +20,53 @@ follows the algorithm set in the spec.</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that a MediaStream constructor follows the algorithm set in the spec", {timeout: 10000});
-t.step(function() {
+let t = async_test("Tests that a MediaStream constructor follows the algorithm set in the spec");
+t.step(() => {
   navigator.mediaDevices.getUserMedia({video: true, audio:true})
-    .then(t.step_func(function (stream) {
-      var stream1 = new MediaStream();
+    .then(t.step_func(stream => {
+      let stream1 = new MediaStream();
       assert_not_equals(stream.id, stream1.id, "Two different MediaStreams have different ids");
-      var stream2 = new MediaStream(stream);
-      assert_not_equals(stream.id, stream2.id, "A MediaStream constructed from another have different ids");
-      var audioTrack1 = stream.getAudioTracks()[0];
-      var videoTrack = stream.getVideoTracks()[0];
-      assert_equals(audioTrack1, stream2.getAudioTracks()[0], "A MediaStream constructed from another share the same audio track");
-      assert_equals(videoTrack, stream2.getVideoTracks()[0], "A MediaStream constructed from another share the same video track");
-      var stream4 = new MediaStream([audioTrack1]);
+      let stream2 = new MediaStream(stream);
+      assert_not_equals(stream.id, stream2.id, "A MediaStream constructed from another has a different id");
+      let audioTrack1 = stream.getAudioTracks()[0];
+      let videoTrack = stream.getVideoTracks()[0];
+      assert_equals(audioTrack1, stream2.getAudioTracks()[0], "A MediaStream constructed from another shares the same audio track");
+      assert_equals(videoTrack, stream2.getVideoTracks()[0], "A MediaStream constructed from another shares the same video track");
+      let stream4 = new MediaStream([audioTrack1]);
       assert_equals(stream4.getTrackById(audioTrack1.id), audioTrack1, "a non-ended track gets added via the MediaStream constructor");
 
-      var audioTrack2 = audioTrack1.clone();
+      let audioTrack2 = audioTrack1.clone();
       audioTrack2.addEventListener("ended", t.unreached_func("ended event should not be fired by MediaStreamTrack.stop()."));
       audioTrack2.stop();
       assert_equals(audioTrack2.readyState, "ended", "a stopped track is marked ended synchronously");
 
-      var stream3 = new MediaStream([audioTrack2, videoTrack]);
+      let stream3 = new MediaStream([audioTrack2, videoTrack]);
       assert_equals(stream3.getTrackById(audioTrack2.id), audioTrack2, "an ended track gets added via the MediaStream constructor");
       assert_equals(stream3.getTrackById(videoTrack.id), videoTrack, "a non-ended track gets added via the MediaStream constructor even if the previous track was ended");
 
-      var stream5 = new MediaStream([audioTrack2]);
+      let stream5 = new MediaStream([audioTrack2]);
       assert_equals(stream5.getTrackById(audioTrack2.id), audioTrack2, "an ended track gets added via the MediaStream constructor");
       assert_false(stream5.active, "a MediaStream created using the MediaStream() constructor whose arguments are lists of MediaStreamTrack objects that are all ended, the MediaStream object MUST be created with its active attribute set to false");
 
+      audioTrack1.stop();
+      assert_equals(audioTrack1.readyState, "ended",
+        "Stopping audioTrack1 marks it ended synchronously");
+
+      videoTrack.stop();
+      assert_equals(videoTrack.readyState, "ended",
+        "Stopping videoTrack marks it ended synchronously");
+
+      assert_false(stream.active,
+        "The original MediaStream is marked inactive synchronously");
+      assert_false(stream1.active,
+        "MediaStream 1 is marked inactive synchronously");
+      assert_false(stream2.active,
+        "MediaStream 2 is marked inactive synchronously");
+      assert_false(stream3.active,
+        "MediaStream 3 is marked inactive synchronously");
+      assert_false(stream4.active,
+        "MediaStream 4 is marked inactive synchronously");
+
       // Use a timeout to detect a misfire of the ended event.
       t.step_timeout(t.step_func_done());
     })
index 94a826a..229de88 100644 (file)
@@ -5,5 +5,8 @@ Description
 This test checks that removinging a track from a MediaStream works as expected.
 
 
+
 PASS Tests that a removal from a MediaStream works as expected 
+PASS Test that removal from a MediaStream fires ended on media elements (video first) 
+FAIL Test that removal from a MediaStream fires ended on media elements (audio first) assert_equals: audio element ended because no more audio tracks expected true but got false
 
index 787af0b..1e9ebbc 100644 (file)
 <p class="instructions">When prompted, accept to share your audio stream, then your video stream.</p>
 <h1 class="instructions">Description</h1>
 <p class="instructions">This test checks that removinging a track from a MediaStream works as expected.</p>
-
+<video id="video" height="120" width="160" autoplay muted></video>
+<audio id="audio" autoplay muted></audio>
 <div id='log'></div>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that a removal from a MediaStream works as expected", {timeout:10000});
-t.step(function () {
-  var audio;
-  navigator.mediaDevices.getUserMedia({audio:true}).then(gotAudio);
-  function gotAudio(stream) {
-     audio = stream;
-     navigator.mediaDevices.getUserMedia({video:true}).then(gotVideo);
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+  const tracks = stream.getTracks();
+  t.add_cleanup(() => tracks.forEach(track => track.stop()));
+  const stream2 = await navigator.mediaDevices.getUserMedia({audio: true});
+  tracks.push(...stream2.getTracks());
+
+  stream.onremovetrack = stream2.onremovetrack = t.step_func(() =>
+    assert_unreached("onremovetrack is not triggered by script itself"));
+
+  assert_equals(stream.getTracks().length, 2, "mediastream starts with 2 tracks");
+  stream.removeTrack(stream.getVideoTracks()[0]);
+  assert_equals(stream.getTracks().length, 1, "mediastream has 1 track left");
+  stream.removeTrack(stream.getAudioTracks()[0]);
+  assert_equals(stream.getTracks().length, 0, "mediastream has no tracks left");
+  stream.removeTrack(stream2.getTracks()[0]); // should not throw
+
+  // Allow time to verify no events fire.
+  await new Promise(r => t.step_timeout(r, 1));
+
+}, "Tests that a removal from a MediaStream works as expected");
+
+async function doesEventFire(t, target, name, ms = 1) {
+  const cookie = {};
+  const value = await Promise.race([
+    new Promise(r => target.addEventListener(name, r, {once: true})),
+    new Promise(r => t.step_timeout(r, ms)).then(() => cookie)
+  ]);
+  return value !== cookie;
+}
+
+const doEventsFire = (t, target1, target2, name, ms = 1) => Promise.all([
+  doesEventFire(t, target1, "ended", ms),
+  doesEventFire(t, target2, "ended", ms)
+]);
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+  const tracks = stream.getTracks();
+
+  audio.srcObject = video.srcObject = stream;
+
+  t.add_cleanup(() => {
+    for (const track of tracks) {
+      track.stop();
+    }
+    audio.srcObject = video.srcObject = null;
+  });
+
+  await Promise.all([
+    new Promise(r => audio.onloadedmetadata = r),
+    new Promise(r => video.onloadedmetadata = r)
+  ]);
+
+  assert_equals(audio.ended, false, "audio element starts out not ended");
+  assert_equals(video.ended, false, "video element starts out not ended");
+
+  stream.removeTrack(stream.getVideoTracks()[0]);
+  {
+    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+    assert_equals(audio.ended, false, "audio element unaffected");
+    assert_equals(audioDidEnd, false, "no audio ended event should fire yet");
+    assert_equals(video.ended, false, "video element keeps going with audio track");
+    assert_equals(videoDidEnd, false, "no video ended event should fire yet");
   }
+  stream.removeTrack(stream.getAudioTracks()[0]);
+  {
+    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+    assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
+    assert_equals(audioDidEnd, true, "go audio ended event");
+    assert_equals(video.ended, true, "video element ended because no more tracks");
+    assert_equals(videoDidEnd, true, "got video ended event");
+  }
+}, "Test that removal from a MediaStream fires ended on media elements (video first)");
+
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+  const tracks = stream.getTracks();
+
+  audio.srcObject = video.srcObject = stream;
 
-  function gotVideo(stream) {
-    var video = stream;
-    video.onremovetrack = function () {
-       assert_unreached("onremovetrack is not triggered when removal of track is triggered by the script itself");
-    };
-    t.step(function () {
-       assert_equals(video.getVideoTracks().length, 1, "video mediastream starts with one video track");
-       video.removeTrack(video.getVideoTracks()[0]);
-       assert_equals(video.getVideoTracks().length, 0, "video mediastream has no video track left");
-       video.removeTrack(audio.getAudioTracks()[0]); // should not throw
-    });
-    t.step(function() {
-       t.done();
-   });
+  t.add_cleanup(() => {
+    for (const track of tracks) {
+      track.stop();
+    }
+    audio.srcObject = video.srcObject = null;
+  });
+
+  await Promise.all([
+    new Promise(r => audio.onloadedmetadata = r),
+    new Promise(r => video.onloadedmetadata = r)
+  ]);
+
+  assert_equals(audio.ended, false, "audio element starts out not ended");
+  assert_equals(video.ended, false, "video element starts out not ended");
+
+  stream.removeTrack(stream.getAudioTracks()[0]);
+  {
+    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+    assert_equals(audio.ended, true, "audio element ended because no more audio tracks");
+    assert_equals(audioDidEnd, true, "got audio ended event");
+    assert_equals(video.ended, false, "video element keeps going with video track");
+    assert_equals(videoDidEnd, false, "no video ended event should fire yet");
   }
-});
+  stream.removeTrack(stream.getVideoTracks()[0]);
+  {
+    const [audioDidEnd, videoDidEnd] = await doEventsFire(t, audio, video, "ended");
+    assert_equals(audio.ended, true, "audio element remains ended from before");
+    assert_equals(audioDidEnd, false, "no second audio ended event should fire");
+    assert_equals(video.ended, true, "video element ended because no more tracks");
+    assert_equals(videoDidEnd, true, "got video ended event");
+  }
+}, "Test that removal from a MediaStream fires ended on media elements (audio first)");
+
 </script>
 </body>
 </html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy-expected.txt
new file mode 100644 (file)
index 0000000..a018aed
--- /dev/null
@@ -0,0 +1,4 @@
+
+FAIL document.featurePolicy.features should advertise camera. undefined is not an object (evaluating 'document.featurePolicy.features')
+FAIL document.featurePolicy.features should advertise microphone. undefined is not an object (evaluating 'document.featurePolicy.features')
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy.html
new file mode 100644 (file)
index 0000000..ef29ae6
--- /dev/null
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<title>Test that accelerometer is advertised in the feature list</title>
+<link rel="help" href="https://w3c.github.io/webappsec-feature-policy/#dom-featurepolicy-features">
+<link rel="help" href="https://w3c.github.io/mediacapture-main/#feature-policy-integration">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+    assert_in_array('camera', document.featurePolicy.features());
+}, 'document.featurePolicy.features should advertise camera.');
+
+test(() => {
+    assert_in_array('microphone', document.featurePolicy.features());
+}, 'document.featurePolicy.features should advertise microphone.');
+</script>
index 0d6123d..8a5d0a1 100644 (file)
@@ -18,7 +18,7 @@ Web Audio API</a>.</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that a disabled audio track in a MediaStream is rendered as silence", {timeout: 200000});
+var t = async_test("Tests that a disabled audio track in a MediaStream is rendered as silence");
 var aud = document.getElementById("aud");
 t.step(function() {
   navigator.mediaDevices.getUserMedia({audio: true}).then(t.step_func(function (stream) {
index 8a75164..21164c8 100644 (file)
@@ -1,4 +1,3 @@
-CONSOLE MESSAGE: line 49: SyntaxError: Unexpected token ')'
 When prompted, accept to share your video stream.
 
 Description
@@ -7,5 +6,7 @@ This test checks that a disabled video track in a MediaStream is rendered as bla
 
 
 
-FAIL A disabled video track is rendered as blackness SyntaxError: Unexpected token ')'
+Harness Error (TIMEOUT), message = null
+
+TIMEOUT Tests that a disabled video track in a MediaStream is rendered as blackness Test timed out
 
index 8aee8e2..769b7a3 100644 (file)
@@ -19,7 +19,7 @@ MediaStream is rendered as blackness.</p>
 <script>
 var vid = document.getElementById("vid");
 var cv = document.createElement("canvas");
-var t = async_test("Tests that a disabled video track in a MediaStream is rendered as blackness", {timeout: 10000});
+var t = async_test("Tests that a disabled video track in a MediaStream is rendered as blackness");
 t.step(function() {
   navigator.mediaDevices.getUserMedia({video: true})
     .then(t.step_func(function (stream) {
@@ -46,7 +46,7 @@ t.step(function() {
       vid.srcObject = stream;
       vid.play();
       vid.addEventListener("loadeddata", testOnceLoadeddata, false);
-    })));
+    }));
 });
 </script>
 </body>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https-expected.txt
new file mode 100644 (file)
index 0000000..798e004
--- /dev/null
@@ -0,0 +1,9 @@
+When prompted, accept to share your video stream.
+
+
+FAIL applyConstraints rejects invalid groupID assert_equals: expected "OverconstrainedError" but got "Error"
+PASS applyConstraints accepts invalid ideal groupID, does not change setting 
+FAIL applyConstraints rejects attempt to switch device using groupId assert_equals: expected "OverconstrainedError" but got "Error"
+FAIL applyConstraints rejects invalid resizeMode assert_unreached: applyConstraints() must fail with invalid resizeMode Reached unreachable code
+PASS applyConstraints accepts invalid ideal resizeMode, does not change setting 
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html
new file mode 100644 (file)
index 0000000..025f827
--- /dev/null
@@ -0,0 +1,79 @@
+<!doctype html>
+<title>MediaStreamTrack applyConstraints</title>
+<p class="instructions">When prompted, accept to share your video stream.</p>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+  'use strict'
+
+  // https://w3c.github.io/mediacapture-main/#dom-mediastreamtrack-applyconstraints
+
+  promise_test(t => {
+    return navigator.mediaDevices.getUserMedia({ video: true })
+      .then(t.step_func(stream => {
+        return stream.getVideoTracks()[0].applyConstraints(
+          { groupId: { exact: "INVALID" } }).then(
+            t.unreached_func('Accepted invalid groupID'),
+            t.step_func(e => {
+              assert_equals(e.name, 'OverconstrainedError');
+              assert_equals(e.constraint, 'groupId');
+            }));
+      }));
+  }, 'applyConstraints rejects invalid groupID');
+
+  promise_test(t => {
+    return navigator.mediaDevices.getUserMedia({ video: true })
+      .then(t.step_func(stream => {
+        var track = stream.getVideoTracks()[0];
+        var groupId = track.getSettings().groupId;
+        return track.applyConstraints({ groupId: "INVALID" }).then(
+          t.step_func(() => {
+            assert_equals(track.getSettings().groupId, groupId);
+          }));
+      }));
+  }, 'applyConstraints accepts invalid ideal groupID, does not change setting');
+
+  promise_test(t => {
+    return navigator.mediaDevices.getUserMedia({ video: true })
+      .then(t.step_func(stream => {
+        var track = stream.getVideoTracks()[0];
+        var groupId = track.getSettings().groupId;
+        return navigator.mediaDevices.enumerateDevices().then(devices => {
+          var anotherDevice = devices.find(device => {
+            return device.kind == "videoinput" && device.groupId != groupId;
+          });
+          if (anotherDevice !== undefined) {
+            return track.applyConstraints(
+              { groupId: { exact: anotherDevice.groupId } }).then(
+                t.unreached_func(),
+                t.step_func(e => {
+                  assert_equals(e.name, 'OverconstrainedError');
+                  assert_equals(e.constraint, 'groupId');
+                }));
+          }
+        });
+      }));
+  }, 'applyConstraints rejects attempt to switch device using groupId');
+
+  promise_test(async t => {
+    const stream = await navigator.mediaDevices.getUserMedia({ video: true });
+    const [track] = stream.getVideoTracks();
+    t.add_cleanup(() => track.stop());
+    try {
+      await track.applyConstraints({ resizeMode: { exact: "INVALID" } });
+      t.unreached_func('applyConstraints() must fail with invalid resizeMode')();
+    } catch (e) {
+      assert_equals(e.name, 'OverconstrainedError');
+      assert_equals(e.constraint, 'resizeMode');
+    }
+  }, 'applyConstraints rejects invalid resizeMode');
+
+  promise_test(async t => {
+    const stream = await navigator.mediaDevices.getUserMedia({ video: true });
+    const [track] = stream.getVideoTracks();
+    t.add_cleanup(() => track.stop());
+    const resizeMode = track.getSettings().resizeMode;
+    await track.applyConstraints({ resizeMode: "INVALID" });
+    assert_equals(track.getSettings().resizeMode, resizeMode);
+  }, 'applyConstraints accepts invalid ideal resizeMode, does not change setting');
+</script>
index 76fcb26..b339646 100644 (file)
@@ -7,5 +7,5 @@ This test checks that the video and audio tracks of MediaStream object returned
 
 Harness Error (TIMEOUT), message = null
 
-TIMEOUT Tests that the video MediaStreamTrack objects are properly ended on permission revocation Test timed out
+TIMEOUT Tests that MediaStreamTracks end properly on permission revocation Test timed out
 
index 3500b03..b27b455 100644 (file)
@@ -17,22 +17,34 @@ correctly set into inactive state when permission is revoked.</p>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that the video MediaStreamTrack objects are properly ended on permission revocation", {timeout: 20000}); // longer timeout since requires user interaction
-t.step(function () {
-  navigator.mediaDevices.getUserMedia({audio: true,video: true}).then(t.step_func(function (stream) {
-    var vidTrack = stream.getVideoTracks()[0];
-    assert_equals(vidTrack.readyState, "live", "The video track object is in live state");
-    var audTrack = stream.getAudioTracks()[0];
-    assert_equals(audTrack.readyState, "live", "The audio track object is in live state");
-    vidTrack.onended = t.step_func(function () {
-        assert_equals(vidTrack.readyState, "ended", "Video track has been ended as expected");
-        assert_equals(audTrack.readyState, "ended", "Audio track has been ended as expected");
-        assert_false(stream.active, "MediaStream has been inactive as expected");
-        t.done();
-      });
-    }), function (error) {}
-  );
-});
+'use strict';
+promise_test(async t => {
+  const stream = await navigator.mediaDevices.getUserMedia({
+    audio: true,
+    video: true,
+  });
+
+  const vidTrack = stream.getVideoTracks()[0];
+  assert_equals(vidTrack.readyState, "live",
+    "The video track object is in live state");
+  const vidEnded = new Promise(r => vidTrack.onended = r);
+  const audTrack = stream.getAudioTracks()[0];
+  assert_equals(audTrack.readyState, "live",
+    "The audio track object is in live state");
+  const audEnded = new Promise(r => audTrack.onended = r);
+
+  await Promise.race([vidEnded, audEnded]);
+  assert_equals(stream.getTracks().filter(t => t.readyState == "ended").length,
+    1, "Only one track is ended after first track's ended event");
+  assert_equals(stream.getTracks().filter(t => t.readyState == "live").length,
+    1, "One track is still live after first track's ended event");
+  assert_true(stream.active, "MediaStream is still active");
+
+  await Promise.all([vidEnded, audEnded]);
+  assert_equals(vidTrack.readyState, "ended", "Video track ended as expected");
+  assert_equals(audTrack.readyState, "ended", "Audio track ended as expected");
+  assert_false(stream.active, "MediaStream has become inactive as expected");
+}, "Tests that MediaStreamTracks end properly on permission revocation");
 </script>
 </body>
 </html>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https-expected.txt
new file mode 100644 (file)
index 0000000..499a535
--- /dev/null
@@ -0,0 +1,72 @@
+
+PASS Setup audio MediaStreamTrack getCapabilities() test for sampleRate 
+PASS Setup audio MediaStreamTrack getCapabilities() test for sampleSize 
+PASS Setup audio MediaStreamTrack getCapabilities() test for echoCancellation 
+PASS Setup audio MediaStreamTrack getCapabilities() test for autoGainControl 
+PASS Setup audio MediaStreamTrack getCapabilities() test for noiseSuppression 
+PASS Setup audio MediaStreamTrack getCapabilities() test for latency 
+PASS Setup audio MediaStreamTrack getCapabilities() test for channelCount 
+PASS Setup audio MediaStreamTrack getCapabilities() test for deviceId 
+PASS Setup audio MediaStreamTrack getCapabilities() test for groupId 
+PASS Setup video MediaStreamTrack getCapabilities() test for width 
+PASS Setup video MediaStreamTrack getCapabilities() test for height 
+PASS Setup video MediaStreamTrack getCapabilities() test for aspectRatio 
+PASS Setup video MediaStreamTrack getCapabilities() test for frameRate 
+PASS Setup video MediaStreamTrack getCapabilities() test for facingMode 
+PASS Setup video MediaStreamTrack getCapabilities() test for resizeMode 
+PASS Setup video MediaStreamTrack getCapabilities() test for deviceId 
+PASS Setup video MediaStreamTrack getCapabilities() test for groupId 
+FAIL Setup audio InputDeviceInfo getCapabilities() test for sampleRate assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for sampleSize assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for echoCancellation assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for autoGainControl assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for noiseSuppression assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for latency assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for channelCount assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for deviceId assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup audio InputDeviceInfo getCapabilities() test for groupId assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for width assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for height assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for aspectRatio assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for frameRate assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for facingMode assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for resizeMode assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for deviceId assert_inherits: property "getCapabilities" not found in prototype chain
+FAIL Setup video InputDeviceInfo getCapabilities() test for groupId assert_inherits: property "getCapabilities" not found in prototype chain
+PASS Audio track getCapabilities() sampleRate property present. 
+PASS Audio track getCapabilities() sampleRate properly supported. 
+FAIL Audio track getCapabilities() sampleSize property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() sampleSize properly supported. assert_equals: expected "object" but got "undefined"
+PASS Audio track getCapabilities() echoCancellation property present. 
+PASS Audio track getCapabilities() echoCancellation properly supported. 
+FAIL Audio track getCapabilities() autoGainControl property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() autoGainControl properly supported. undefined is not an object (evaluating 'capability.length')
+FAIL Audio track getCapabilities() noiseSuppression property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() noiseSuppression properly supported. undefined is not an object (evaluating 'capability.length')
+FAIL Audio track getCapabilities() latency property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() latency properly supported. assert_equals: expected "object" but got "undefined"
+FAIL Audio track getCapabilities() channelCount property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() channelCount properly supported. assert_equals: expected "object" but got "undefined"
+PASS Audio track getCapabilities() deviceId property present. 
+PASS Audio track getCapabilities() deviceId properly supported. 
+FAIL Audio track getCapabilities() groupId property present. assert_true: expected true got false
+FAIL Audio track getCapabilities() groupId properly supported. assert_equals: expected "string" but got "undefined"
+PASS Video track getCapabilities() width property present. 
+PASS Video track getCapabilities() width properly supported. 
+PASS Video track getCapabilities() height property present. 
+PASS Video track getCapabilities() height properly supported. 
+PASS Video track getCapabilities() aspectRatio property present. 
+PASS Video track getCapabilities() aspectRatio properly supported. 
+PASS Video track getCapabilities() frameRate property present. 
+PASS Video track getCapabilities() frameRate properly supported. 
+PASS Video track getCapabilities() facingMode property present. 
+PASS Video track getCapabilities() facingMode properly supported. 
+FAIL Video track getCapabilities() resizeMode property present. assert_true: expected true got false
+FAIL Video track getCapabilities() resizeMode properly supported. undefined is not an object (evaluating 'capability.forEach')
+FAIL Video track getCapabilities() resizeMode properly supported. Value: none undefined is not an object (evaluating 'expected.indexOf')
+FAIL Video track getCapabilities() resizeMode properly supported. Value: crop-and-scale undefined is not an object (evaluating 'expected.indexOf')
+PASS Video track getCapabilities() deviceId property present. 
+PASS Video track getCapabilities() deviceId properly supported. 
+FAIL Video track getCapabilities() groupId property present. assert_true: expected true got false
+FAIL Video track getCapabilities() groupId properly supported. assert_equals: expected "string" but got "undefined"
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
new file mode 100644 (file)
index 0000000..2334514
--- /dev/null
@@ -0,0 +1,149 @@
+<!doctype html>
+<title>MediaStreamTrack and InputDeviceInfo GetCapabilities</title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script>
+
+const audioProperties = [
+  {name: "sampleRate", type: "number"},
+  {name: "sampleSize", type: "number"},
+  {name: "echoCancellation", type: "boolean"},
+  {name: "autoGainControl", type: "boolean"},
+  {name: "noiseSuppression", type: "boolean"},
+  {name: "latency", type: "number"},
+  {name: "channelCount", type: "number"},
+  {name: "deviceId", type: "string"},
+  {name: "groupId", type: "string"}
+];
+
+const videoProperties = [
+  {name: "width", type: "number"},
+  {name: "height", type: "number"},
+  {name: "aspectRatio", type: "number"},
+  {name: "frameRate", type: "number"},
+  {name: "facingMode", type: "enum-any", validValues: ["user", "environment", "left", "right"]},
+  {name: "resizeMode", type: "enum-all", validValues: ["none", "crop-and-scale"]},
+  {name: "deviceId", type: "string"},
+  {name: "groupId", type: "string"},
+];
+
+function verifyBooleanCapability(capability) {
+  assert_less_than_equal(capability.length, 2);
+  capability.forEach(c => assert_equals(typeof c, "boolean"));
+}
+
+function verifyNumberCapability(capability) {
+    assert_equals(typeof capability, "object");
+    assert_equals(Object.keys(capability).length, 2);
+    assert_true(capability.hasOwnProperty('min'));
+    assert_true(capability.hasOwnProperty('max'));
+    assert_less_than_equal(capability.min, capability.max);
+}
+
+// Verify that any value provided by an enum capability is in the set of valid
+// values.
+function verifyEnumAnyCapability(capability, enumMembers) {
+  capability.forEach(c => {
+    assert_equals(typeof c, "string");
+    assert_in_array(c, enumMembers);
+  });
+}
+
+// Verify that all required values are supported by a capability.
+function verifyEnumAllCapability(capability, enumMembers, testNamePrefix) {
+  enumMembers.forEach(member => {
+    test(() => {
+      assert_in_array(member, capability);
+    }, testNamePrefix + " Value: " + member);
+  });
+}
+
+function testCapabilities(capabilities, property, testNamePrefix) {
+  let testName = testNamePrefix + " " + property.name;
+  test(() => {
+    assert_true(capabilities.hasOwnProperty(property.name));
+  }, testName + " property present.");
+
+  const capability = capabilities[property.name];
+  testName += " properly supported.";
+  if (property.type == "string") {
+    test(() => {
+      assert_equals(typeof capability, "string");
+    }, testName);
+  }
+
+  if (property.type == "boolean") {
+    test(() => {
+      verifyBooleanCapability(capability);
+    }, testName);
+  }
+
+  if (property.type == "number") {
+    test(() => {
+      verifyNumberCapability(capability);
+    }, testName);
+  }
+
+  if (property.type.startsWith("enum")) {
+    test(() => {
+      verifyEnumAnyCapability(capability, property.validValues);
+    }, testName);
+
+    if (property.type == "enum-all") {
+      verifyEnumAllCapability(capability, property.validValues, testName);
+    }
+  }
+}
+
+{
+  audioProperties.forEach(property => {
+    promise_test(async t => {
+      const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+      t.add_cleanup(() => stream.getAudioTracks()[0].stop());
+      const audioCapabilities = stream.getAudioTracks()[0].getCapabilities();
+      testCapabilities(audioCapabilities, property, "Audio track getCapabilities()");
+    }, "Setup audio MediaStreamTrack getCapabilities() test for " + property.name);
+  });
+
+  videoProperties.forEach(property => {
+    promise_test(async t => {
+      const stream = await navigator.mediaDevices.getUserMedia({video: true});
+      t.add_cleanup(() => stream.getVideoTracks()[0].stop());
+      const audioCapabilities = stream.getVideoTracks()[0].getCapabilities();
+      testCapabilities(audioCapabilities, property, "Video track getCapabilities()");
+    }, "Setup video MediaStreamTrack getCapabilities() test for " + property.name);
+  });
+}
+
+{
+  audioProperties.forEach(property => {
+    promise_test(async t => {
+      const devices = await navigator.mediaDevices.enumerateDevices();
+      for (const device of devices) {
+        // Test only one device.
+        if (device.kind == "audioinput") {
+          assert_inherits(device, "getCapabilities");
+          const capabilities = device.getCapabilities();
+          testCapabilities(capabilities, property, "Audio device getCapabilities()");
+          break;
+        }
+      }
+    }, "Setup audio InputDeviceInfo getCapabilities() test for " + property.name);
+  });
+
+  videoProperties.forEach(property => {
+    promise_test(async t => {
+      const devices = await navigator.mediaDevices.enumerateDevices();
+      for (const device of devices) {
+        // Test only one device.
+        if (device.kind == "videoinput") {
+          assert_inherits(device, "getCapabilities");
+          const capabilities = device.getCapabilities();
+          testCapabilities(capabilities, property, "Video device getCapabilities()");
+          break;
+        }
+      }
+    }, "Setup video InputDeviceInfo getCapabilities() test for " + property.name);
+  });
+}
+</script>
index fa05c3e..05bca35 100644 (file)
@@ -2,5 +2,23 @@ When prompted, accept to share your video stream.
 
 
 PASS A device can be opened twice and have the same device ID 
-PASS A device can be opened twice with different resolutions 
+PASS A device can be opened twice with different resolutions requested 
+FAIL groupId is correctly reported by getSettings() for all input devices assert_equals: expected (string) "" but got (undefined) undefined
+PASS deviceId is reported by getSettings() for getUserMedia() audio tracks 
+FAIL groupId is reported by getSettings() for getUserMedia() audio tracks assert_equals: groupId should exist and it should be a string. expected "string" but got "undefined"
+PASS sampleRate is reported by getSettings() for getUserMedia() audio tracks 
+FAIL sampleSize is reported by getSettings() for getUserMedia() audio tracks assert_equals: sampleSize should exist and it should be a number. expected "number" but got "undefined"
+PASS echoCancellation is reported by getSettings() for getUserMedia() audio tracks 
+FAIL autoGainControl is reported by getSettings() for getUserMedia() audio tracks assert_equals: autoGainControl should exist and it should be a boolean. expected "boolean" but got "undefined"
+FAIL noiseSuppression is reported by getSettings() for getUserMedia() audio tracks assert_equals: noiseSuppression should exist and it should be a boolean. expected "boolean" but got "undefined"
+FAIL latency is reported by getSettings() for getUserMedia() audio tracks assert_equals: latency should exist and it should be a number. expected "number" but got "undefined"
+FAIL channelCount is reported by getSettings() for getUserMedia() audio tracks assert_equals: channelCount should exist and it should be a number. expected "number" but got "undefined"
+PASS deviceId is reported by getSettings() for getUserMedia() video tracks 
+FAIL groupId is reported by getSettings() for getUserMedia() video tracks assert_equals: groupId should exist and it should be a string. expected "string" but got "undefined"
+PASS width is reported by getSettings() for getUserMedia() video tracks 
+PASS height is reported by getSettings() for getUserMedia() video tracks 
+FAIL aspectRatio is reported by getSettings() for getUserMedia() video tracks assert_equals: aspectRatio should exist and it should be a number. expected "number" but got "undefined"
+PASS frameRate is reported by getSettings() for getUserMedia() video tracks 
+PASS facingMode is reported by getSettings() for getUserMedia() video tracks 
+FAIL resizeMode is reported by getSettings() for getUserMedia() video tracks assert_equals: resizeMode should exist and it should be a string. expected "string" but got "undefined"
 
index 42674ba..1bc1f9b 100644 (file)
@@ -1,6 +1,7 @@
 <!doctype html>
 <title>MediaStreamTrack GetSettings</title>
 <p class="instructions">When prompted, accept to share your video stream.</p>
+<meta name=timeout content=long>
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
 
   // https://w3c.github.io/mediacapture-main/archives/20170605/getusermedia.html
 
-  promise_test(t => {
-    const constraints = {
+  async function createTrackAndGetSettings(t, kind) {
+    const constraints = {};
+    constraints[kind] = true;
+    const stream = await navigator.mediaDevices.getUserMedia(constraints);
+    assert_equals(stream.getTracks().length, 1);
+    t.add_cleanup(() => stream.getTracks()[0].stop());
+    return stream.getTracks()[0].getSettings();
+  }
+
+  promise_test(async t => {
+    const mediaStream1 = await navigator.mediaDevices.getUserMedia({
       video: true,
+      audio: false,
+    });
+    t.add_cleanup(() => mediaStream1.getVideoTracks()[0].stop());
+    const settings1 = mediaStream1.getVideoTracks()[0].getSettings();
+
+    const mediaStream2 = await navigator.mediaDevices.getUserMedia({
+      video: {
+        deviceId: {exact: settings1.deviceId},
+      },
       audio: false
-    };
-
-    return navigator.mediaDevices.getUserMedia(constraints)
-    .then(mediaStream => {
-      const settings1 = mediaStream.getVideoTracks()[0].getSettings();
-      const videoConstraints = {
-        deviceId: settings1.deviceId
-      };
-
-      return navigator.mediaDevices.getUserMedia({
-        video: videoConstraints,
-        audio: false
-      }).then(mediaStream => {
-        const settings2 = mediaStream.getVideoTracks()[0].getSettings();
-        assert_equals(settings1.deviceId, settings2.deviceId);
-      });
     });
+    t.add_cleanup(() => mediaStream2.getVideoTracks()[0].stop());
+    const settings2 = mediaStream2.getVideoTracks()[0].getSettings();
+
+    assert_equals(settings1.deviceId, settings2.deviceId);
   }, 'A device can be opened twice and have the same device ID');
 
-  promise_test(t => {
-    const constraints = {
+  promise_test(async t => {
+    const mediaStream1 = await navigator.mediaDevices.getUserMedia({
       video: true,
-      audio: false
-    };
+      audio: false,
+    });
+    t.add_cleanup(() => mediaStream1.getVideoTracks()[0].stop());
+    const settings1 = mediaStream1.getVideoTracks()[0].getSettings();
 
-    return navigator.mediaDevices.getUserMedia(constraints)
-    .then(mediaStream => {
-      const settings1 = mediaStream.getVideoTracks()[0].getSettings();
-      const videoConstraints = {
-        deviceId: settings1.deviceId,
+    const mediaStream2 = await navigator.mediaDevices.getUserMedia({
+      video: {
+        deviceId: {exact: settings1.deviceId},
         width: {
-          exact: settings1.width / 2
-        }
-      };
-
-      return navigator.mediaDevices.getUserMedia({
-        video: videoConstraints,
-        audio: false
-      }).then(mediaStream => {
-        const settings2 = mediaStream.getVideoTracks()[0].getSettings();
-        assert_equals(settings1.deviceId, settings2.deviceId);
-        assert_equals(settings1.width / 2, settings2.width);
-      });
+          ideal: settings1.width / 2,
+        },
+      },
+      audio: false
     });
-  }, 'A device can be opened twice with different resolutions');
+    t.add_cleanup(() => mediaStream2.getVideoTracks()[0].stop());
+    const settings2 = mediaStream2.getVideoTracks()[0].getSettings();
+
+    assert_equals(settings1.deviceId, settings2.deviceId);
+    assert_between_inclusive(settings2.width, settings1.width / 2, settings1.width);
+  }, 'A device can be opened twice with different resolutions requested');
+
+  promise_test(async t => {
+    const devices = await navigator.mediaDevices.enumerateDevices();
+    const inputDevices = devices.filter(d => d.kind != "audiooutput");
+    assert_greater_than(inputDevices.length, 0);
+    for (const device of inputDevices) {
+      const device_id_constraint = {deviceId: {exact: device.deviceId}};
+      const constraints = device.kind == "audioinput"
+        ? {audio: device_id_constraint}
+        : {video: device_id_constraint};
+
+      const stream = await navigator.mediaDevices.getUserMedia(constraints);
+      assert_equals(stream.getTracks()[0].getSettings().groupId,
+                    device.groupId);
+      assert_greater_than(device.groupId.length, 0);
+    }
+  }, 'groupId is correctly reported by getSettings() for all input devices');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.deviceId), "string",
+                  "deviceId should exist and it should be a string.");
+  }, 'deviceId is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.groupId), "string",
+                  "groupId should exist and it should be a string.");
+  }, 'groupId is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.sampleRate), "number",
+                  "sampleRate should exist and it should be a number.");
+    assert_greater_than(settings.sampleRate, 0);
+  }, 'sampleRate is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.sampleSize), "number",
+                  "sampleSize should exist and it should be a number.");
+    assert_greater_than(settings.sampleSize, 0);
+  }, 'sampleSize is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.echoCancellation), "boolean",
+                  "echoCancellation should exist and it should be a boolean.");
+  }, 'echoCancellation is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.autoGainControl), "boolean",
+                  "autoGainControl should exist and it should be a boolean.");
+  }, 'autoGainControl is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.noiseSuppression), "boolean",
+                  "noiseSuppression should exist and it should be a boolean.");
+  }, 'noiseSuppression is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.latency), "number",
+                  "latency should exist and it should be a number.");
+    assert_greater_than_equal(settings.latency,0);
+  }, 'latency is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "audio");
+    assert_equals(typeof(settings.channelCount), "number",
+                  "channelCount should exist and it should be a number.");
+    assert_greater_than(settings.channelCount, 0);
+  }, 'channelCount is reported by getSettings() for getUserMedia() audio tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.deviceId), "string",
+                  "deviceId should exist and it should be a string.");
+  }, 'deviceId is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.groupId), "string",
+                  "groupId should exist and it should be a string.");
+  }, 'groupId is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.width), "number",
+                  "width should exist and it should be a number.");
+    assert_true(Number.isInteger(settings.width), "width should be an integer.");
+    assert_greater_than_equal(settings.width, 0);;
+  }, 'width is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.height), "number",
+                  "height should exist and it should be a number.");
+    assert_true(Number.isInteger(settings.height), "height should be an integer.");
+    assert_greater_than_equal(settings.height, 0);
+  }, 'height is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.aspectRatio), "number",
+                  "aspectRatio should exist and it should be a number.");
+    assert_greater_than_equal(settings.aspectRatio, 0);
+  }, 'aspectRatio is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.frameRate), "number",
+                  "frameRate should exist and it should be a number.");
+    assert_greater_than_equal(settings.frameRate, 0);
+  }, 'frameRate is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    // facingMode not treated as mandatory because not all platforms provide
+    // this information.
+    if (settings.facingMode) {
+      assert_equals(typeof(settings.facingMode), "string",
+                  "If facingMode is provided it should be a string.");
+      assert_in_array(settings.facingMode,
+                  ['user', 'environment', 'left', 'right']);
+    }
+  }, 'facingMode is reported by getSettings() for getUserMedia() video tracks');
+
+  promise_test(async t => {
+    const settings = await createTrackAndGetSettings(t, "video");
+    assert_equals(typeof(settings.resizeMode), "string",
+                "resizeMode should exist and it should be a string.");
+    assert_in_array(settings.resizeMode, ['none', 'crop-and-scale']);
+  }, 'resizeMode is reported by getSettings() for getUserMedia() video tracks');
 </script>
index 85c72fe..e7a687d 100644 (file)
@@ -14,7 +14,7 @@
 <script src=/resources/testharness.js></script>
 <script src=/resources/testharnessreport.js></script>
 <script>
-var t = async_test("Tests that distinct mediastream tracks have distinct ids ", {timeout: 10000});
+var t = async_test("Tests that distinct mediastream tracks have distinct ids ");
 t.step(function () {
   navigator.mediaDevices.getUserMedia({video: true, audio: true})
     .then(t.step_func(gotStream), t.step_func(function(error) {t.assert_unreached("Access to audio and video stream is granted");}));
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/OWNERS b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/OWNERS
deleted file mode 100644 (file)
index 25688fa..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-@agouaillard
-@alvestrand
-@dontcallmedom
-@eric-carlson
-@youennf
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.https-expected.txt
new file mode 100644 (file)
index 0000000..21c95fa
--- /dev/null
@@ -0,0 +1,8 @@
+
+PASS webkitMediaStream interface should not exist 
+PASS navigator.webkitGetUserMedia should not exist 
+PASS navigator.mozGetUserMedia should not exist 
+PASS Passing MediaStream to URL.createObjectURL() should throw 
+PASS MediaStream.onactive should not exist 
+PASS MediaStream.oninactive should not exist 
+
@@ -15,4 +15,19 @@ test(function() {
 test(function() {
   assert_false("mozGetUserMedia" in navigator);
 }, "navigator.mozGetUserMedia should not exist");
+
+test(() => {
+  const mediaStream = new MediaStream();
+  assert_throws(new TypeError(), () => URL.createObjectURL(mediaStream));
+}, "Passing MediaStream to URL.createObjectURL() should throw");
+
+test(() => {
+  const mediaStream = new MediaStream();
+  assert_false("onactive" in mediaStream);
+}, "MediaStream.onactive should not exist");
+
+test(() => {
+  const mediaStream = new MediaStream();
+  assert_false("oninactive" in mediaStream);
+}, "MediaStream.oninactive should not exist");
 </script>
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window-expected.txt
new file mode 100644 (file)
index 0000000..137e91d
--- /dev/null
@@ -0,0 +1,162 @@
+
+PASS idl_test setup 
+PASS Partial interface Navigator: original interface defined 
+PASS Partial interface Navigator[2]: original interface defined 
+PASS Partial interface MediaDevices: original interface defined 
+PASS MediaStream interface: existence and properties of interface object 
+PASS MediaStream interface object length 
+PASS MediaStream interface object name 
+PASS MediaStream interface: existence and properties of interface prototype object 
+PASS MediaStream interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaStream interface: existence and properties of interface prototype object's @@unscopables property 
+PASS MediaStream interface: attribute id 
+PASS MediaStream interface: operation getAudioTracks() 
+PASS MediaStream interface: operation getVideoTracks() 
+PASS MediaStream interface: operation getTracks() 
+PASS MediaStream interface: operation getTrackById(DOMString) 
+PASS MediaStream interface: operation addTrack(MediaStreamTrack) 
+PASS MediaStream interface: operation removeTrack(MediaStreamTrack) 
+PASS MediaStream interface: operation clone() 
+PASS MediaStream interface: attribute active 
+PASS MediaStream interface: attribute onaddtrack 
+PASS MediaStream interface: attribute onremovetrack 
+PASS MediaStream must be primary interface of stream 
+PASS Stringification of stream 
+PASS MediaStream interface: stream must inherit property "id" with the proper type 
+PASS MediaStream interface: stream must inherit property "getAudioTracks()" with the proper type 
+PASS MediaStream interface: stream must inherit property "getVideoTracks()" with the proper type 
+PASS MediaStream interface: stream must inherit property "getTracks()" with the proper type 
+PASS MediaStream interface: stream must inherit property "getTrackById(DOMString)" with the proper type 
+PASS MediaStream interface: calling getTrackById(DOMString) on stream with too few arguments must throw TypeError 
+PASS MediaStream interface: stream must inherit property "addTrack(MediaStreamTrack)" with the proper type 
+PASS MediaStream interface: calling addTrack(MediaStreamTrack) on stream with too few arguments must throw TypeError 
+PASS MediaStream interface: stream must inherit property "removeTrack(MediaStreamTrack)" with the proper type 
+PASS MediaStream interface: calling removeTrack(MediaStreamTrack) on stream with too few arguments must throw TypeError 
+PASS MediaStream interface: stream must inherit property "clone()" with the proper type 
+PASS MediaStream interface: stream must inherit property "active" with the proper type 
+PASS MediaStream interface: stream must inherit property "onaddtrack" with the proper type 
+PASS MediaStream interface: stream must inherit property "onremovetrack" with the proper type 
+PASS MediaStream must be primary interface of new MediaStream() 
+PASS Stringification of new MediaStream() 
+PASS MediaStream interface: new MediaStream() must inherit property "id" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "getAudioTracks()" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "getVideoTracks()" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "getTracks()" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "getTrackById(DOMString)" with the proper type 
+PASS MediaStream interface: calling getTrackById(DOMString) on new MediaStream() with too few arguments must throw TypeError 
+PASS MediaStream interface: new MediaStream() must inherit property "addTrack(MediaStreamTrack)" with the proper type 
+PASS MediaStream interface: calling addTrack(MediaStreamTrack) on new MediaStream() with too few arguments must throw TypeError 
+PASS MediaStream interface: new MediaStream() must inherit property "removeTrack(MediaStreamTrack)" with the proper type 
+PASS MediaStream interface: calling removeTrack(MediaStreamTrack) on new MediaStream() with too few arguments must throw TypeError 
+PASS MediaStream interface: new MediaStream() must inherit property "clone()" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "active" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "onaddtrack" with the proper type 
+PASS MediaStream interface: new MediaStream() must inherit property "onremovetrack" with the proper type 
+PASS MediaStreamTrack interface: existence and properties of interface object 
+PASS MediaStreamTrack interface object length 
+PASS MediaStreamTrack interface object name 
+PASS MediaStreamTrack interface: existence and properties of interface prototype object 
+PASS MediaStreamTrack interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaStreamTrack interface: existence and properties of interface prototype object's @@unscopables property 
+PASS MediaStreamTrack interface: attribute kind 
+PASS MediaStreamTrack interface: attribute id 
+PASS MediaStreamTrack interface: attribute label 
+PASS MediaStreamTrack interface: attribute enabled 
+PASS MediaStreamTrack interface: attribute muted 
+PASS MediaStreamTrack interface: attribute onmute 
+PASS MediaStreamTrack interface: attribute onunmute 
+PASS MediaStreamTrack interface: attribute readyState 
+PASS MediaStreamTrack interface: attribute onended 
+PASS MediaStreamTrack interface: operation clone() 
+PASS MediaStreamTrack interface: operation stop() 
+PASS MediaStreamTrack interface: operation getCapabilities() 
+PASS MediaStreamTrack interface: operation getConstraints() 
+PASS MediaStreamTrack interface: operation getSettings() 
+PASS MediaStreamTrack interface: operation applyConstraints(MediaTrackConstraints) 
+PASS MediaStreamTrack must be primary interface of track 
+PASS Stringification of track 
+PASS MediaStreamTrack interface: track must inherit property "kind" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "id" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "label" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "enabled" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "muted" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "onmute" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "onunmute" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "readyState" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "onended" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "clone()" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "stop()" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "getCapabilities()" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "getConstraints()" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "getSettings()" with the proper type 
+PASS MediaStreamTrack interface: track must inherit property "applyConstraints(MediaTrackConstraints)" with the proper type 
+PASS MediaStreamTrack interface: calling applyConstraints(MediaTrackConstraints) on track with too few arguments must throw TypeError 
+PASS MediaStreamTrackEvent interface: existence and properties of interface object 
+PASS MediaStreamTrackEvent interface object length 
+PASS MediaStreamTrackEvent interface object name 
+PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object 
+PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaStreamTrackEvent interface: existence and properties of interface prototype object's @@unscopables property 
+PASS MediaStreamTrackEvent interface: attribute track 
+PASS MediaStreamTrackEvent must be primary interface of trackEvent 
+PASS Stringification of trackEvent 
+PASS MediaStreamTrackEvent interface: trackEvent must inherit property "track" with the proper type 
+PASS MediaDevices interface: existence and properties of interface object 
+PASS MediaDevices interface object length 
+PASS MediaDevices interface object name 
+PASS MediaDevices interface: existence and properties of interface prototype object 
+PASS MediaDevices interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaDevices interface: existence and properties of interface prototype object's @@unscopables property 
+PASS MediaDevices interface: attribute ondevicechange 
+PASS MediaDevices interface: operation enumerateDevices() 
+PASS MediaDevices interface: operation getSupportedConstraints() 
+PASS MediaDevices interface: operation getUserMedia(MediaStreamConstraints) 
+PASS MediaDevices must be primary interface of navigator.mediaDevices 
+PASS Stringification of navigator.mediaDevices 
+PASS MediaDevices interface: navigator.mediaDevices must inherit property "ondevicechange" with the proper type 
+PASS MediaDevices interface: navigator.mediaDevices must inherit property "enumerateDevices()" with the proper type 
+PASS MediaDevices interface: navigator.mediaDevices must inherit property "getSupportedConstraints()" with the proper type 
+PASS MediaDevices interface: navigator.mediaDevices must inherit property "getUserMedia(MediaStreamConstraints)" with the proper type 
+PASS MediaDevices interface: calling getUserMedia(MediaStreamConstraints) on navigator.mediaDevices with too few arguments must throw TypeError 
+PASS MediaDeviceInfo interface: existence and properties of interface object 
+PASS MediaDeviceInfo interface object length 
+PASS MediaDeviceInfo interface object name 
+PASS MediaDeviceInfo interface: existence and properties of interface prototype object 
+PASS MediaDeviceInfo interface: existence and properties of interface prototype object's "constructor" property 
+PASS MediaDeviceInfo interface: existence and properties of interface prototype object's @@unscopables property 
+PASS MediaDeviceInfo interface: attribute deviceId 
+PASS MediaDeviceInfo interface: attribute kind 
+PASS MediaDeviceInfo interface: attribute label 
+PASS MediaDeviceInfo interface: attribute groupId 
+PASS MediaDeviceInfo interface: operation toJSON() 
+FAIL InputDeviceInfo interface: existence and properties of interface object assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface object length assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface object name assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface: existence and properties of interface prototype object assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface: existence and properties of interface prototype object's @@unscopables property assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo interface: operation getCapabilities() assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL InputDeviceInfo must be primary interface of audioinput assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL Stringification of audioinput assert_equals: class string of audioinput expected "[object InputDeviceInfo]" but got "[object MediaDeviceInfo]"
+FAIL InputDeviceInfo interface: audioinput must inherit property "getCapabilities()" with the proper type assert_inherits: property "getCapabilities" not found in prototype chain
+PASS MediaDeviceInfo interface: audioinput must inherit property "deviceId" with the proper type 
+PASS MediaDeviceInfo interface: audioinput must inherit property "kind" with the proper type 
+PASS MediaDeviceInfo interface: audioinput must inherit property "label" with the proper type 
+PASS MediaDeviceInfo interface: audioinput must inherit property "groupId" with the proper type 
+PASS MediaDeviceInfo interface: audioinput must inherit property "toJSON()" with the proper type 
+PASS MediaDeviceInfo interface: default toJSON operation on audioinput 
+FAIL InputDeviceInfo must be primary interface of videoinput assert_own_property: self does not have own property "InputDeviceInfo" expected property "InputDeviceInfo" missing
+FAIL Stringification of videoinput assert_equals: class string of videoinput expected "[object InputDeviceInfo]" but got "[object MediaDeviceInfo]"
+FAIL InputDeviceInfo interface: videoinput must inherit property "getCapabilities()" with the proper type assert_inherits: property "getCapabilities" not found in prototype chain
+PASS MediaDeviceInfo interface: videoinput must inherit property "deviceId" with the proper type 
+PASS MediaDeviceInfo interface: videoinput must inherit property "kind" with the proper type 
+PASS MediaDeviceInfo interface: videoinput must inherit property "label" with the proper type 
+PASS MediaDeviceInfo interface: videoinput must inherit property "groupId" with the proper type 
+PASS MediaDeviceInfo interface: videoinput must inherit property "toJSON()" with the proper type 
+PASS MediaDeviceInfo interface: default toJSON operation on videoinput 
+PASS Navigator interface: attribute mediaDevices 
+FAIL Navigator interface: operation getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback) assert_own_property: interface prototype object missing non-static operation expected property "getUserMedia" missing
+PASS Navigator interface: navigator must inherit property "mediaDevices" with the proper type 
+FAIL Navigator interface: navigator must inherit property "getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback)" with the proper type assert_inherits: property "getUserMedia" not found in prototype chain
+FAIL Navigator interface: calling getUserMedia(MediaStreamConstraints, NavigatorUserMediaSuccessCallback, NavigatorUserMediaErrorCallback) on navigator with too few arguments must throw TypeError assert_inherits: property "getUserMedia" not found in prototype chain
+
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.html b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.html
new file mode 100644 (file)
index 0000000..2382913
--- /dev/null
@@ -0,0 +1 @@
+<!-- This file is required for WebKit test infrastructure to run the templated test -->
\ No newline at end of file
diff --git a/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.js b/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.js
new file mode 100644 (file)
index 0000000..594e112
--- /dev/null
@@ -0,0 +1,48 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+'use strict';
+
+// https://w3c.github.io/mediacapture-main/
+
+idl_test(
+  ['mediacapture-streams'],
+  ['dom', 'html'],
+  async idl_array => {
+    const inputDevices = [];
+    const outputDevices = [];
+    try {
+      const list = await navigator.mediaDevices.enumerateDevices();
+      for (const device of list) {
+        if (device.kind in self) {
+          continue;
+        }
+        assert_in_array(device.kind, ['audioinput', 'videoinput', 'audiooutput']);
+        self[device.kind] = device;
+        if (device.kind.endsWith('input')) {
+          inputDevices.push(device.kind);
+        } else {
+          outputDevices.push(device.kind);
+        }
+      }
+    } catch (e) {}
+
+    try {
+      self.stream = await navigator.mediaDevices.getUserMedia({audio: true});
+      self.track = stream.getTracks()[0];
+      self.trackEvent = new MediaStreamTrackEvent("type", {
+        track: track,
+      });
+    } catch (e) {}
+
+    idl_array.add_objects({
+      InputDeviceInfo: inputDevices,
+      MediaStream: ['stream', 'new MediaStream()'],
+      Navigator: ['navigator'],
+      MediaDevices: ['navigator.mediaDevices'],
+      MediaDeviceInfo: outputDevices,
+      MediaStreamTrack: ['track'],
+      MediaStreamTrackEvent: ['trackEvent'],
+    });
+  }
+);
index ec25ad3..5419146 100644 (file)
@@ -1,7 +1,7 @@
 The tests in this directory were imported from the W3C repository.
 Do NOT modify these tests directly in WebKit.
 Instead, create a pull request on the WPT github:
-       https://github.com/w3c/web-platform-tests
+       https://github.com/web-platform-tests/wpt
 
 Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport
 
@@ -18,31 +18,43 @@ List of files:
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-deny.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-empty-option-param.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-impossible-constraint.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-invalid-facing-mode.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-non-applicable-constraint.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-optional-constraint.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-trivial-constraint.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/GUM-unknownkey-option-param.https.html
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-all.html
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-IDL-enumerateDevices.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/META.yml
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-SecureContext.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-camera.https.html.headers
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-not-allowed-mic.https.html.headers
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices-returned-objects.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-enumerateDevices.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getSupportedConstraints.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaDevices-getUserMedia.https.html
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-firstframe.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-preload-none-manual.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-MediaElement-srcObject.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-add-audio-track.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-audio-only.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-clone.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-default-feature-policy.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-finished-add.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-gettrackid.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-id-manual.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-idl.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-removetrack.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-supported-by-feature-policy.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStream-video-only.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-audio-is-silence.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-MediaElement-disabled-video-is-black.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-applyConstraints.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-end-manual.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getCapabilities.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-id.https.html
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-idl.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-init.https.html
 /LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrackEvent-constructor.https.html
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/OWNERS
-/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/historical.https.html
+/LayoutTests/imported/w3c/web-platform-tests/mediacapture-streams/idlharness.https.window.js
index 4ab5c25..d6826d2 100644 (file)
     "imported/w3c/web-platform-tests/media-source/mediasource-redundant-seek.html": [
         "slow"
     ],
+    "imported/w3c/web-platform-tests/mediacapture-streams/MediaStreamTrack-getSettings.https.html": [
+        "slow"
+    ],
     "imported/w3c/web-platform-tests/payment-request/payment-request-constructor-crash.https.html": [
         "slow"
     ],