Merge pull request #3220 from w3c/plh/page-visibility/onvisibilitychange
Plh/page visibility/onvisibilitychange
diff --git a/user-timing/measure.html b/user-timing/measure.html
index 4175dbb..8f2a618 100644
--- a/user-timing/measure.html
+++ b/user-timing/measure.html
@@ -95,7 +95,7 @@
// create the test end mark using the test delay; this will allow for a significant difference between
// the mark values that should be represented in the duration of measures using these marks
- setTimeout(measure_test_cb, measureTestDelay);
+ step_timeout(measure_test_cb, measureTestDelay);
}
}
diff --git a/user-timing/measure_navigation_timing.html b/user-timing/measure_navigation_timing.html
index 93b6dc2..fa472fd 100644
--- a/user-timing/measure_navigation_timing.html
+++ b/user-timing/measure_navigation_timing.html
@@ -92,7 +92,7 @@
// create the test end mark using the test delay; this will allow for a significant difference between
// the mark values that should be represented in the duration of measures using these marks
- setTimeout(measure_test_cb, measureTestDelay);
+ step_timeout(measure_test_cb, measureTestDelay);
}
}
diff --git a/webrtc/RTCPeerConnection-addIceCandidate.html b/webrtc/RTCPeerConnection-addIceCandidate.html
index 1e27f27..e2fc6fd 100644
--- a/webrtc/RTCPeerConnection-addIceCandidate.html
+++ b/webrtc/RTCPeerConnection-addIceCandidate.html
@@ -169,27 +169,6 @@
}, 'Add ICE candidate before setting remote description should reject with InvalidStateError');
/*
- 4.3.1.2. Enqueue an operation
- 7.1. If connection's [[isClosed]] slot is true, abort these steps.
-
- 4.3.2. addIceCandidate
- 4. Return the result of enqueuing the following steps:
- 1. If remoteDescription is null return a promise rejected with a
- newly created InvalidStateError.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
-
- const promise = pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid, sdpMLineIndex, ufrag
- });
-
- pc.close();
- return promise;
- }, 'Add candidate when remote description is null should never resolve when pc is closed');
-
- /*
Success cases
*/
promise_test(t => {
@@ -523,63 +502,6 @@
})));
}, 'Add candidate with sdpMid belonging to different ufrag should reject with OperationError');
- /*
- 4.3.2. addIceCandidate
- 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
- with a newly created TypeError.
- 4. Return the result of enqueuing the following steps
-
- (Rejects because step 3 comes first)
-
- this test is being deferred until w3c/webrtc-pc#1345 is resolved
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => {
- const promise = pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: null,
- sdpMLineIndex: null
- });
-
- pc.close();
- return promise_rejects(t, new TypeError(), promise);
- });
- }, 'Add candidate with both sdpMid and sdpMLineIndex null should still reject with TypeError after pc is closed');
- */
-
- /*
- 4.3.1.2. Enqueue an operation
- 7.1. If connection's [[isClosed]] slot is true, abort these steps.
-
- 4.3.2. addIceCandidate
- 4. Return the result of enqueuing the following steps
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => {
- const promise = pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid, sdpMLineIndex, ufrag
- });
-
- pc.close();
-
- // When pc is closed, the remote description is not modified
- // even if succeed
- t.step_timeout(t.step_func(() => {
- assert_false(pc.remoteDescription.sdp.includes(candidateLine1),
- 'Candidate should not be added to SDP because pc is closed');
- }), 80);
-
- return promise;
- });
- }, 'Add valid candidate should never resolve when pc is closed');
-
test_never_resolve(t => {
const pc = new RTCPeerConnection();
diff --git a/webrtc/RTCPeerConnection-onnegotiationneeded.html b/webrtc/RTCPeerConnection-onnegotiationneeded.html
index fb9fcbf..fbf3d5a 100644
--- a/webrtc/RTCPeerConnection-onnegotiationneeded.html
+++ b/webrtc/RTCPeerConnection-onnegotiationneeded.html
@@ -120,20 +120,6 @@
return awaitNegotiation(pc);
}, 'task for negotiationneeded event should be enqueued for next tick');
- /*
- 4.7.3. Updating the Negotiation-Needed flag
-
- To update the negotiation-needed flag
- 6. Queue a task that runs the following steps:
- 1. If connection's [[isClosed]] slot is true, abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- pc.createDataChannel('test');
- pc.close();
- return awaitNegotiation(pc);
- }, 'negotiationneeded event should not fire if connection is closed');
-
test_never_resolve(t => {
const pc = new RTCPeerConnection();
pc.createDataChannel('foo');
@@ -216,7 +202,6 @@
2.2.10. If connection's signaling state is now stable, update the negotiation-needed
flag. If connection's [[NegotiationNeeded]] slot was true both before and after
this update, queue a task that runs the following steps:
- 1. If connection's [[IsClosed]] slot is true, abort these steps.
2. If connection's [[NegotiationNeeded]] slot is false, abort these steps.
3. Fire a simple event named negotiationneeded at connection.
*/
@@ -241,7 +226,6 @@
4.7.3. Updating the Negotiation-Needed flag
To update the negotiation-needed flag
- 1. If connection's [[isClosed]] slot is true, abort these steps.
3. If the result of checking if negotiation is needed is "false",
clear the negotiation-needed flag by setting connection's
[[needNegotiation]] slot to false, and abort these steps.
@@ -291,6 +275,12 @@
stop
11. Update the negotiation-needed flag for connection.
+
+ Untestable
+ 4.7.3. Updating the Negotiation-Needed flag
+ 1. If connection's [[isClosed]] slot is true, abort these steps.
+ 6. Queue a task that runs the following steps:
+ 1. If connection's [[isClosed]] slot is true, abort these steps.
*/
</script>
diff --git a/webrtc/RTCPeerConnection-ontrack.html b/webrtc/RTCPeerConnection-ontrack.html
index 22e9d28..6610139 100644
--- a/webrtc/RTCPeerConnection-ontrack.html
+++ b/webrtc/RTCPeerConnection-ontrack.html
@@ -3,16 +3,103 @@
<title>RTCPeerConnection.prototype.ontrack</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
+<script src="RTCPeerConnection-helper.js"></script>
<script>
'use strict';
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // getTrackFromUserMedia
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.8. If description is set as a remote description, then run the following
+ steps for each media description in description:
+ 3. Set transceiver's mid value to the mid of the corresponding media
+ description. If the media description has no MID, and transceiver's
+ mid is unset, generate a random value as described in [JSEP] (section 5.9.).
+ 4. If the direction of the media description is sendrecv or sendonly, and
+ transceiver.receiver.track has not yet been fired in a track event,
+ process the remote track for the media description, given transceiver.
+
+ 5.1.1. Processing Remote MediaStreamTracks
+ To process the remote track for an incoming media description [JSEP]
+ (section 5.9.) given RTCRtpTransceiver transceiver, the user agent MUST
+ run the following steps:
+
+ 1. Let connection be the RTCPeerConnection object associated with transceiver.
+ 2. Let streams be a list of MediaStream objects that the media description
+ indicates the MediaStreamTrack belongs to.
+ 3. Add track to all MediaStream objects in streams.
+ 4. Queue a task to fire an event named track with transceiver, track, and
+ streams at the connection object.
+
+ 5.7. RTCTrackEvent
+ [Constructor(DOMString type, RTCTrackEventInit eventInitDict)]
+ interface RTCTrackEvent : Event {
+ readonly attribute RTCRtpReceiver receiver;
+ readonly attribute MediaStreamTrack track;
+ [SameObject]
+ readonly attribute FrozenArray<MediaStream> streams;
+ readonly attribute RTCRtpTransceiver transceiver;
+ };
+
+ [mediacapture-main]
+ 4.2. MediaStream
+ interface MediaStream : EventTarget {
+ readonly attribute DOMString id;
+ sequence<MediaStreamTrack> getTracks();
+ ...
+ };
+
+ [mediacapture-main]
+ 4.3. MediaStreamTrack
+ interface MediaStreamTrack : EventTarget {
+ readonly attribute DOMString kind;
+ readonly attribute DOMString id;
+ ...
+ };
+ */
+
+ function validateTrackEvent(trackEvent) {
+ const { receiver, track, streams, transceiver } = trackEvent;
+
+ assert_true(track instanceof MediaStreamTrack,
+ 'Expect track to be instance of MediaStreamTrack');
+
+ assert_true(Array.isArray(streams),
+ 'Expect streams to be an array');
+
+ for(const mediaStream of streams) {
+ assert_true(mediaStream instanceof MediaStream,
+ 'Expect elements in streams to be instance of MediaStream');
+
+ assert_true(mediaStream.getTracks().includes(track),
+ 'Expect each mediaStream to have track as one of their tracks');
+ }
+
+ assert_true(receiver instanceof RTCRtpReceiver,
+ 'Expect trackEvent.receiver to be defined and is instance of RTCRtpReceiver');
+
+ assert_equals(receiver.track, track,
+ 'Expect trackEvent.receiver.track to be the same as trackEvent.track');
+
+ assert_true(transceiver instanceof RTCRtpTransceiver,
+ 'Expect trackEvent.transceiver to be defined and is instance of RTCRtpTransceiver');
+
+ assert_equals(transceiver.receiver, receiver,
+ 'Expect trackEvent.transceiver.receiver to be the same as trackEvent.receiver');
+ }
+
// tests that ontrack is called and parses the msid information from the SDP and creates
// the streams with matching identifiers.
async_test(t => {
const pc = new RTCPeerConnection();
// Fail the test if the ontrack event handler is not implemented
- assert_own_property(pc, 'ontrack', 'Expect pc to have ontrack event handler attribute');
+ assert_idl_attribute(pc, 'ontrack', 'Expect pc to have ontrack event handler attribute');
const sdp = `v=0
o=- 166855176514521964 2 IN IP4 127.0.0.1
@@ -34,16 +121,150 @@
a=ssrc:1001 cname:some
`;
- pc.ontrack = t.step_func(event => {
- assert_equals(event.streams.length, 1, 'the track belongs to one MediaStream');
- assert_equals(event.streams[0].id, 'stream1', 'the stream name is parsed from the MSID line');
+ pc.ontrack = t.step_func(trackEvent => {
+ const { streams, track, transceiver } = trackEvent;
+
+ assert_equals(streams.length, 1,
+ 'the track belongs to one MediaStream');
+
+ const [stream] = streams;
+ assert_equals(stream.id, 'stream1',
+ 'Expect stream.id to be the same as specified in the a=msid line');
+
+ assert_equals(track.kind, 'audio',
+ 'Expect track.kind to be audio');
+
+ validateTrackEvent(trackEvent);
+
+ assert_equals(transceiver.direction, 'recvonly',
+ 'Expect transceiver.direction to be reverse of sendonly (recvonly)');
+
t.done();
});
- pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp}))
+ pc.setRemoteDescription({ type: 'offer', sdp })
.catch(t.step_func(err => {
assert_unreached('Error ' + err.name + ': ' + err.message);
}));
}, 'setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed.');
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+
+ assert_idl_attribute(pc, 'ontrack', 'Expect pc to have ontrack event handler attribute');
+
+ const sdp = `v=0
+o=- 166855176514521964 2 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=msid-semantic:WMS *
+m=audio 9 UDP/TLS/RTP/SAVPF 111
+c=IN IP4 0.0.0.0
+a=rtcp:9 IN IP4 0.0.0.0
+a=ice-ufrag:someufrag
+a=ice-pwd:somelongpwdwithenoughrandomness
+a=fingerprint:sha-256 8C:71:B3:8D:A5:38:FD:8F:A4:2E:A2:65:6C:86:52:BC:E0:6E:94:F2:9F:7C:4D:B5:DF:AF:AA:6F:44:90:8D:F4
+a=setup:actpass
+a=rtcp-mux
+a=mid:mid1
+a=recvonly
+a=rtpmap:111 opus/48000/2
+a=msid:stream1 track1
+a=ssrc:1001 cname:some
+`;
+
+ pc.ontrack = t.unreached_func('ontrack event should not fire for track with recvonly direction');
+
+ pc.setRemoteDescription({ type: 'offer', sdp })
+ .catch(t.step_func(err => {
+ assert_unreached('Error ' + err.name + ': ' + err.message);
+ }))
+ .then(t.step_func(() => {
+ t.step_timeout(t.step_func_done(), 100);
+ }));
+
+ }, 'setRemoteDescription() with m= line of recvonly direction should not trigger track event');
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ pc2.ontrack = t.step_func(trackEvent => {
+ const { track } = trackEvent;
+
+ assert_equals(track.kind, 'audio',
+ 'Expect track.kind to be audio');
+
+ validateTrackEvent(trackEvent);
+
+ t.done();
+ });
+
+ return getTrackFromUserMedia('audio')
+ .then(([track, mediaStream]) => {
+ pc1.addTrack(track, mediaStream);
+
+ return pc1.createOffer()
+ .then(offer => pc2.setRemoteDescription(offer));
+ })
+ .catch(t.step_func(err => {
+ assert_unreached('Error ' + err.name + ': ' + err.message);
+ }));
+
+ }, 'addTrack() should cause remote connection to fire ontrack when setRemoteDescription()');
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ pc2.ontrack = t.step_func(trackEvent => {
+ const { track } = trackEvent;
+
+ assert_equals(track.kind, 'video',
+ 'Expect track.kind to be video');
+
+ validateTrackEvent(trackEvent);
+
+ t.done();
+ });
+
+ pc1.addTransceiver('video');
+
+ return pc1.createOffer()
+ .then(offer => pc2.setRemoteDescription(offer))
+ .catch(t.step_func(err => {
+ assert_unreached('Error ' + err.name + ': ' + err.message);
+ }));
+
+ }, `addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()`);
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ pc2.ontrack = t.step_func(trackEvent => {
+ const { track } = trackEvent;
+
+ assert_equals(track.kind, 'video',
+ 'Expect track.kind to be video');
+
+ validateTrackEvent(trackEvent);
+
+ t.done();
+ });
+
+ pc1.addTransceiver('audio', { direction: 'inactive' });
+ pc2.ontrack = t.unreached_func('ontrack event should not fire for track with inactive direction');
+
+ return pc1.createOffer()
+ .then(offer => pc2.setRemoteDescription(offer))
+ .catch(t.step_func(err => {
+ assert_unreached('Error ' + err.name + ': ' + err.message);
+ }))
+ .then(t.step_func(() => {
+ t.step_timeout(t.step_func_done(), 100);
+ }));
+
+ }, `addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()`);
+
</script>
diff --git a/webrtc/RTCPeerConnection-setLocalDescription.html b/webrtc/RTCPeerConnection-setLocalDescription.html
index d11936b..d201859 100644
--- a/webrtc/RTCPeerConnection-setLocalDescription.html
+++ b/webrtc/RTCPeerConnection-setLocalDescription.html
@@ -146,24 +146,8 @@
}))));
}, 'Creating and setting offer multiple times should succeed');
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.1. If connection's [[IsClosed]] slot is true, then abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
-
- return pc.createOffer()
- .then(offer => {
- const promise = pc.setLocalDescription(offer);
- pc.close();
- return promise;
- });
- }, 'setLocalDescription(offer) should never resolve if connection is closed in parallel')
-
/* setLocalDescription(answer) */
-
/*
4.3.1.6. Set the RTCSessionSessionDescription
2. If description is set as a local description, then run one of the following
diff --git a/webrtc/RTCPeerConnection-setRemoteDescription.html b/webrtc/RTCPeerConnection-setRemoteDescription.html
index 50a719d..a913d2c 100644
--- a/webrtc/RTCPeerConnection-setRemoteDescription.html
+++ b/webrtc/RTCPeerConnection-setRemoteDescription.html
@@ -91,21 +91,6 @@
/*
4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.1. If connection's [[IsClosed]] slot is true, then abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
-
- return generateOffer()
- .then(offer => {
- const promise = pc.setRemoteDescription(offer);
- pc.close();
- return promise;
- });
- }, 'setRemoteDescription(offer) should never resolve if connection is closed in parallel')
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
2.1.4. If the content of description is not valid SDP syntax, then reject p with
an RTCError (with errorDetail set to "sdp-syntax-error" and the
sdpLineNumber attribute set to the line number in the SDP where the syntax
diff --git a/webrtc/RTCRtpSender-replaceTrack.html b/webrtc/RTCRtpSender-replaceTrack.html
index 0ec3a81..587ca57 100644
--- a/webrtc/RTCRtpSender-replaceTrack.html
+++ b/webrtc/RTCRtpSender-replaceTrack.html
@@ -220,29 +220,6 @@
}, 'Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track');
/*
- 5.2. replaceTrack
- Not 8. If transceiver is not yet associated with a media description
- [JSEP] (section 3.4.1.), then set sender's track attribute to
- withTrack, and return a promise resolved with undefined.
- 10. Run the following steps in parallel:
- 3. Queue a task that runs the following steps:
- 1. If connection's [[isClosed]] slot is true, abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- const track = generateMediaStreamTrack('audio');
- const { transceiver: { sender } } = pc.addTransceiver('audio');
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => {
- const promise = sender.replaceTrack(track);
- pc.close();
- return promise;
- });
- }, 'replaceTrack should never resolve if connection is closed in parallel');
-
- /*
TODO
5.2. replaceTrack
To avoid track identifiers changing on the remote receiving end when
@@ -266,5 +243,7 @@
negotiating. Otherwise, have the sender switch seamlessly to
transmitting withTrack instead of the sender's existing track,
without negotiating.
+ 3. Queue a task that runs the following steps:
+ 1. If connection's [[isClosed]] slot is true, abort these steps.
*/
</script>
diff --git a/webrtc/coverage/set-session-description.txt b/webrtc/coverage/set-session-description.txt
index 1071778..0f7d65b 100644
--- a/webrtc/coverage/set-session-description.txt
+++ b/webrtc/coverage/set-session-description.txt
@@ -14,8 +14,7 @@
1. If the process to apply description fails for any reason, then user agent
MUST queue a task that runs the following steps:
- [RTCPeerConnection-setLocalDescription]
- [RTCPeerConnection-setRemoteDescription]
+ [Untestable]
1. If connection's [[IsClosed]] slot is true, then abort these steps.
[Untestable]
@@ -47,8 +46,7 @@
2. If description is applied successfully, the user agent MUST queue a task
that runs the following steps:
- [RTCPeerConnection-setLocalDescription]
- [RTCPeerConnection-setRemoteDescription]
+ [Untestable]
1. If connection's [[isClosed]] slot is true, then abort these steps.
[RTCPeerConnection-setLocalDescription]
@@ -158,7 +156,7 @@
2. Set transceiver's mid value to the mid of the corresponding media
description.
- [TODO]
+ [RTCPeerConnection-ontrack]
8. If description is set as a remote description, then run the following steps
for each media description in description:
@@ -166,26 +164,26 @@
1. As described by [JSEP] (section 5.9.), attempt to find an existing
RTCRtpTransceiver object, transceiver, to represent the media description.
- [TODO]
+ [RTCPeerConnection-ontrack]
2. If no suitable transceiver is found (transceiver is unset), run the following
steps:
- [TODO]
+ [RTCPeerConnection-ontrack]
1. Create an RTCRtpSender, sender, from the media description.
- [TODO]
+ [RTCPeerConnection-ontrack]
2. Create an RTCRtpReceiver, receiver, from the media description.
- [TODO]
+ [RTCPeerConnection-ontrack]
3. Create an RTCRtpTransceiver with sender, receiver and direction, and let
transceiver be the result.
- [TODO]
+ [RTCPeerConnection-ontrack]
3. Set transceiver's mid value to the mid of the corresponding media description.
If the media description has no MID, and transceiver's mid is unset, generate
a random value as described in [JSEP] (section 5.9.).
- [TODO]
+ [RTCPeerConnection-ontrack]
4. If the direction of the media description is sendrecv or sendonly, and
transceiver.receiver.track has not yet been fired in a track event, process
the remote track for the media description, given transceiver.
@@ -218,7 +216,7 @@
flag. If connection's [[NegotiationNeeded]] slot was true both before and after
this update, queue a task that runs the following steps:
- [RTCPeerConnection-onnegotiationneeded]
+ [Untestable]
1. If connection's [[IsClosed]] slot is true, abort these steps.
[RTCPeerConnection-onnegotiationneeded]
@@ -236,7 +234,7 @@
Coverage Report
- Tested 28
- Not Tested 22
+ Tested 35
+ Not Tested 15
Untestable 8
Total 58