</capabilities>
<testcase purpose="RTCCertificate-postMessage" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCCertificate-postMessage">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCCertificate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCCertificate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-bundlePolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceCandidatePoolSize" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceServers" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceTransportPolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-rtcpMuxPolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-insertDTMF.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-ontonechange-long.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange-long.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-ontonechange.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-bufferedAmount" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-close" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-close">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-iceRestart" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-id" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-id">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-send-blob-order" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-send-blob-order">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send-blob-order.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send-blob-order.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-send" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-send">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannelEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDtlsTransport-getRemoteCertificates" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDtlsTransport-getRemoteCertificates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDtlsTransport-state" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDtlsTransport-state">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCError" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCError">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceCandidate-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceConnectionState-candidate-pair.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceConnectionState-candidate-pair.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceTransport" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceTransport">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-SLD-SRD-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-SLD-SRD-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-add-track-no-deadlock.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-add-track-no-deadlock.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate-connectionSetup" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addTransceiver.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-canTrickleIceCandidates" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-candidate-in-sdp.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-candidate-in-sdp.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-capture-video.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-capture-video.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-capture-video.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-capture-video.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-connectionState.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createAnswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createDataChannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createOffer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-description-attributes-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-explicit-rollback-iceGatheringState" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-generateCertificate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-getTransceivers" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-getTransceivers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-helper-test" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-helper-test">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceConnectionState-disconnected.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState-disconnected.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceConnectionState.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceGatheringState" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-mandatory-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-ondatachannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onicecandidateerror.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onicecandidateerror.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onnegotiationneeded" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onsignalingstatechanged.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-ontrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-operations.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation-stress-glare-linear.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation-stress-glare-linear.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation-stress-glare-linear.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation-stress-glare-linear.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation-stress-glare.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation-stress-glare.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation-stress-glare.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation-stress-glare.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-plan-b-is-not-supported" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-plan-b-is-not-supported">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-plan-b-is-not-supported.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-plan-b-is-not-supported.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-relay-canvas.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-relay-canvas.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-relay-canvas.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-relay-canvas.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-remote-track-mute.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-remote-track-mute.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-remote-track-mute.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-remote-track-mute.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-removeTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-restartIce-onnegotiationneeded.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce-onnegotiationneeded.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-restartIce.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setDescription-transceiver" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-parameterless.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-pranswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-rollback" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-nomsid" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-nomsid">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-pranswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-replaceTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-rollback" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-simulcast.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-simulcast.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-simulcast.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-simulcast.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-tracks.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<!-- <testcase purpose="RTCPeerConnection-track-stats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase> -->
<testcase purpose="RTCPeerConnection-transceivers.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-videoDetectorTest" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-videoDetectorTest">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnectionIceErrorEvent" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnectionIceErrorEvent">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-codecs" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-encodings" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-headerExtensions" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-headerExtensions">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-rtcp" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-transactionId" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getCapabilities" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getContributingSources.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getParameters" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getSynchronizationSources.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getSynchronizationSources.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getSynchronizationSources.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-encode-same-track-twice.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-encode-same-track-twice.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-getCapabilities" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-replaceTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-setParameters" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-setParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-setStreams.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-transport.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-direction" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-setCodecPreferences" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-stop" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-events" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-events">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-maxChannels" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-maxMessageSize" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCTrackEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCTrackEvent-fire" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCTrackEvent-fire">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="getstats" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="getstats">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/getstats.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="historical" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="historical">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="no-media-call" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="no-media-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/no-media-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="promises-call" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="promises-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/promises-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="receiver-track-live.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="receiver-track-live.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simplecall-no-ssrcs.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simplecall-no-ssrcs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simplecall.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simplecall.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<!-- <testcase purpose="RTCPeerConnection-addStream.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addStream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase> -->
<testcase purpose="RTCPeerConnection-createOffer-offerToReceive" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-with-OfferToReceive-options.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="onaddstream.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="onaddstream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="basic.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="basic.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="h264.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="h264.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="setParameters-active.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="setParameters-active.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="vp8.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="vp8.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-payloadTypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-payloadTypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="bundle.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="bundle.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="candidate-exchange.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="candidate-exchange.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="crypto-suite.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="crypto-suite.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="dtls-fingerprint-validation" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="dtls-fingerprint-validation">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="handover-datachannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="handover-datachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="handover" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="handover">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="ice-state.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="ice-state.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="ice-ufragpwd" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="ice-ufragpwd">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="jsep-initial-offer.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="jsep-initial-offer.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="missing-fields" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="missing-fields">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="msid-parse" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="msid-parse">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-clockrate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-clockrate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-demuxing" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-demuxing">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-extension-support" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-extension-support">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-extension-support.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-extension-support.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-payloadtypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-payloadtypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="sctp-format" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="sctp-format">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simulcast-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simulcast-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simulcast-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simulcast-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="split.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="split.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="unknown-mediatypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="unknown-mediatypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="video-codecs.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="video-codecs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="vp8-fmtp" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="vp8-fmtp">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/vp8-fmtp.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/vp8-fmtp.html</test_script_entry>
</description>
<specs>
<spec>
</capabilities>
<testcase purpose="RTCCertificate-postMessage" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCCertificate-postMessage">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCCertificate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCCertificate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-bundlePolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceCandidatePoolSize" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceServers" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-iceTransportPolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCConfiguration-rtcpMuxPolicy" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-insertDTMF.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-ontonechange-long.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange-long.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDTMFSender-ontonechange.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-bufferedAmount" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-close" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-close">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-iceRestart" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-id" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-id">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-send-blob-order" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-send-blob-order">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send-blob-order.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send-blob-order.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannel-send" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannel-send">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDataChannelEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDtlsTransport-getRemoteCertificates" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDtlsTransport-getRemoteCertificates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCDtlsTransport-state" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCDtlsTransport-state">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCError" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCError">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceCandidate-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceConnectionState-candidate-pair.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceConnectionState-candidate-pair.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCIceTransport" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCIceTransport">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-SLD-SRD-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-SLD-SRD-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-add-track-no-deadlock.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-add-track-no-deadlock.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate-connectionSetup" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addIceCandidate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addTransceiver.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-canTrickleIceCandidates" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-candidate-in-sdp.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-candidate-in-sdp.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-capture-video.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-capture-video.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-capture-video.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-capture-video.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-connectionState.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createAnswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createDataChannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createOffer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-description-attributes-timing.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-explicit-rollback-iceGatheringState" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-generateCertificate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-getTransceivers" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-getTransceivers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-helper-test" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-helper-test">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceConnectionState-disconnected.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState-disconnected.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceConnectionState.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-iceGatheringState" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-mandatory-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-ondatachannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onicecandidateerror.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onicecandidateerror.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onnegotiationneeded" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-onsignalingstatechanged.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-ontrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-operations.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation-stress-glare-linear.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation-stress-glare-linear.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation-stress-glare-linear.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation-stress-glare-linear.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation-stress-glare.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation-stress-glare.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation-stress-glare.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation-stress-glare.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-perfect-negotiation.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-perfect-negotiation.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-perfect-negotiation.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-perfect-negotiation.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-plan-b-is-not-supported" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-plan-b-is-not-supported">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-plan-b-is-not-supported.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-plan-b-is-not-supported.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-relay-canvas.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-relay-canvas.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-relay-canvas.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-relay-canvas.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-remote-track-mute.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-remote-track-mute.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-remote-track-mute.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-remote-track-mute.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-removeTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-restartIce-onnegotiationneeded.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce-onnegotiationneeded.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-restartIce.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setDescription-transceiver" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-parameterless.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-pranswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription-rollback" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setLocalDescription" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-nomsid" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-nomsid">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-pranswer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-replaceTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-rollback" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-simulcast.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-simulcast.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-simulcast.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-simulcast.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription-tracks.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-setRemoteDescription" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-track-stats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-transceivers.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="RTCPeerConnection-videoDetectorTest" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-videoDetectorTest">
+ <testcase purpose="RTCPeerConnection-videoDetectorTest" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="manual" priority="P1" id="RTCPeerConnection-videoDetectorTest">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnectionIceErrorEvent" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnectionIceErrorEvent">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-codecs" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-encodings" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-headerExtensions" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-headerExtensions">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-rtcp" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpParameters-transactionId" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getCapabilities" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getContributingSources.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getParameters" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpReceiver-getSynchronizationSources.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpReceiver-getSynchronizationSources.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getSynchronizationSources.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getSynchronizationSources.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-encode-same-track-twice.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-encode-same-track-twice.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-getCapabilities" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-replaceTrack.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-setParameters" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-setParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-setStreams.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender-transport.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpSender.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpSender.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-direction" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-setCodecPreferences" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-stop" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-events" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-events">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-maxChannels" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCSctpTransport-maxMessageSize" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCTrackEvent-constructor" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCTrackEvent-fire" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCTrackEvent-fire">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="getstats" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="getstats">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/getstats.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="historical" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="historical">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="no-media-call" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="no-media-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/no-media-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="promises-call" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="promises-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/promises-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="receiver-track-live.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="receiver-track-live.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simplecall-no-ssrcs.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simplecall-no-ssrcs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simplecall.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simplecall.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-addStream.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-addStream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-createOffer-offerToReceive" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCRtpTransceiver-with-OfferToReceive-options.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="onaddstream.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="onaddstream.https">
+ <testcase purpose="onaddstream.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="onaddstream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="basic.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="basic.https">
+ <testcase purpose="basic.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="basic.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="getStats.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="h264.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="h264.https">
+ <testcase purpose="h264.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="h264.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="setParameters-active.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="setParameters-active.https">
+ <testcase purpose="setParameters-active.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="setParameters-active.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="vp8.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="vp8.https">
+ <testcase purpose="vp8.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="vp8.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="RTCPeerConnection-payloadTypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="RTCPeerConnection-payloadTypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="bundle.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="bundle.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="candidate-exchange.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="candidate-exchange.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="crypto-suite.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="crypto-suite.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="dtls-fingerprint-validation" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="dtls-fingerprint-validation">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="handover-datachannel" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="handover-datachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="handover" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="handover">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="ice-state.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="ice-state.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="ice-ufragpwd" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="ice-ufragpwd">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="jsep-initial-offer.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="jsep-initial-offer.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="missing-fields" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="missing-fields">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="msid-parse" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="msid-parse">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html</test_script_entry>
</description>
<specs>
<spec>
</spec>
</specs>
</testcase>
- <testcase purpose="rtp-clockrate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-clockrate">
+ <testcase purpose="rtp-clockrate" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" onload_delay="60" execution_type="auto" priority="P1" id="rtp-clockrate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-demuxing" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-demuxing">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-extension-support" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-extension-support">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-extension-support.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-extension-support.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="rtp-payloadtypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="rtp-payloadtypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="sctp-format" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="sctp-format">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simulcast-answer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simulcast-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="simulcast-offer" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="simulcast-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="split.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="split.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="unknown-mediatypes" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="unknown-mediatypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="video-codecs.https" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="video-codecs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html</test_script_entry>
</description>
<specs>
<spec>
</testcase>
<testcase purpose="vp8-fmtp" type="compliance" status="approved" component="W3C_HTML5 APIs/TBD/ServiceWorkers" execution_type="auto" priority="P1" id="vp8-fmtp">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/vp8-fmtp.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/vp8-fmtp.html</test_script_entry>
</description>
<specs>
<spec>
</capabilities>
<testcase purpose="Check same-origin RTCCertificate serialization" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="RTCCertificate-postMessage">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setConfiguration with different set of certs should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificate should have at least one fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Default bundlePolicy should be balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: undefined }) should have bundlePolicy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'balanced' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'max-compat' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'max-bundle' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial default bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: balanced }) with initial default bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'balanced' }) with initial bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-compat should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-bundle' }) with initial bundlePolicy max-bundle should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: null }) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'invalid' }) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-bundle should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial bundlePolicy max-bundle should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose=" Initialize a new RTCPeerConnection with no iceCandidatePoolSize" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 255" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: -1 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 256 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 255" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to -1 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 256 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default configuration.iceServers of undefined" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - {} should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - {} should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: undefined } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: undefined } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [] } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [] } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [null] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [null] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [undefined] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [undefined] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [{}] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [{}] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with stun server should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with stun server should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with stun server array should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with stun server array should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server, username, credential should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server, username, credential should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with "" url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with "" url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with ["stun:stun1.example.net", ""] url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with ["stun:stun1.example.net", ""] url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with relative url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with relative url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with http url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with http url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default iceTransportPolicy all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: undefined }) should have default iceTransportPolicy all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: 'all' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: 'relay' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial iceTransportPolicy relay should set new value to all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with invalid iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with invalid iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with none iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with none iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with null iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with null iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default rtcpMuxPolicy require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: undefined }) should have default rtcpMuxPolicy require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: 'require' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' }) may succeed or throw NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with { rtcpMuxPolicy: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with { rtcpMuxPolicy: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with { rtcpMuxPolicy: 'invalid' } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with { rtcpMuxPolicy: 'invalid' } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ rtcpMuxPolicy: 'negotiate' }) with initial rtcpMuxPolicy require should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ rtcpMuxPolicy: 'require' }) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription throws InvalidAccessError when called with an offer without rtcp-mux and rtcpMuxPolicy is set to require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription throws InvalidAccessError when called with an answer without rtcp-mux and rtcpMuxPolicy is set to require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should succeed if tones contains valid DTMF characters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver is stopped" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() after remove and close should reject" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF with duration greater than 6000 should be clamped to 6000" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="RTCDTMFSender-ontonechange-long.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with default duration and intertoneGap should fire tonechange events at the expected time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with explicit duration and intertoneGap should fire tonechange events at the expected time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF('') should not fire any tonechange event, including for '' tone" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with duration less than 40 should be clamped to 40" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with interToneGap less than 30 should be clamped to 30" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF with comma should delay next tonechange event for a constant 2000ms" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Tone change event constructor works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Tone change event with unexpected name should not crash" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount initial value should be 0 for both peers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should increase to byte length of encodedunicode string sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should increase to byte length of buffer sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should not decrease immediately after initiating closure" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should not decrease after closing the peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires after send() is complete" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamount is data.length on send(data)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamount returns the same amount if no more data is" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires only once after multiple consecutive send() calls" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires after each sent message" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount initial value should be 0 for both peers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should increase to byte length of encodedunicode string sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should increase to byte length of buffer sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should not decrease immediately after initiating closure" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should not decrease after closing the peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires after send() is complete" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamount is data.length on send(data)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamount returns the same amount if no more data is" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires only once after multiple consecutive send() calls" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires after each sent message" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Close datachannel causes onclosing and onclose to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Close datachannel causes closing and close event to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error to be called on datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection after datachannel close causes no events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error on many channels, datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Close negotiated datachannel causes onclosing and onclose to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Close negotiated datachannel causes closing and close event to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error to be called on negotiated datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection after negotiated datachannel close causes no events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error on many channels, negotiated datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel remains usable after ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel remains usable at each step of an ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS client uses odd data channel IDs" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS server uses even data channel IDs" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiation with a specific ID should not work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Odd/even role should not be violated when mixing with negotiated channels" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling send() when data channel is in connecting state should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send simple string and receive as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send unicode string and receive as unicode string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should ignore binaryType and always receive string message as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send an empty string and receive an empty string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send Uint8Array message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send simple string and receive as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send unicode string and receive as unicode string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should ignore binaryType and always receive string message as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send an empty string and receive an empty string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send Uint8Array message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor without a required argument." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with channel passed as null." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with a channel passed as undefined." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with full arguments." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDtlsTransport.prototype.getRemoteCertificates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-getRemoteCertificates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS transport goes to connected state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="close() causes the local transport to close immediately" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="close() causes the other end's DTLS transport to close" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor with errorDetail and message" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor's message argument is optional" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor throws TypeError if arguments are missing" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor throws TypeError if the errorDetail is invalid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.name is 'OperationError'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.code is 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.errorDetail is readonly." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCErrorInit.errorDetail is the only required attribute" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({})" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with manually filled default values" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: null, sdpMLineIndex: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '' })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with valid candidate string only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: 'audio' })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMLineIndex: 0 })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with valid candidate string and sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with nondefault values for all fields" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with nondefault values for all fields, tcp candidate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid sdpMLineIndex" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="On ICE connected, getStats() contains a connected candidate-pair" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceConnectionState-candidate-pair.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Unconnected iceTransport should have empty remote candidates and selected pair" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceTransport">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription and setRemoteDescription are not racy" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-SLD-SRD-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection addTrack does not deadlock." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-add-track-no-deadlock.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added dynamically; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added at PC1; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added at PC2; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate is not resolved first if 2x setLocalDescription operations are pending" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate and setLocalDescription are resolved in the correct order, as defined by the operations chain specification" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="onicecandidate fires after resolving setLocalDescription in offerer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="onicecandidate fires after resolving setLocalDescription in answerer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate({"candidate":"","sdpMid":null,"sdpMLineIndex":null}) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate(undefined) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate(null) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate({}) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Add ICE candidate after setting remote description should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Add ICE candidate with RTCIceCandidate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMid should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMid and RTCIceCandidate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMLineIndex should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate for first media stream with null usernameFragment should add candidate to first media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding multiple candidates should add candidates to their corresponding media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with a candidate and neither sdpMid nor sdpMLineIndex should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid candidate string should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid sdpMid should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid sdpMLineIndex should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="Invalid sdpMLineIndex should be ignored if valid sdpMid is provided" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate for media stream 2 with null usernameFragment should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid candidate string should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack when pc is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and no stream should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and single stream should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and multiple streams should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding the same track multiple times should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender that has not been used to send should reuse the sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender that has been used to send should create new sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender with null track, different kind, and recvonly direction should create new sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding more tracks does not generate more candidates if bundled" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling addTrack while sRD(offer) is pending should allow the new remote transceiver to be the same one that addTrack creates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="When addTrack is called while sRD is in progress, and both addTrack and sRD add a transceiver of different media types, the addTrack transceiver should come first, and then the sRD transceiver." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with string argument as invalid kind should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio') should return an audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video') should return a video transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with direction sendonly should have result transceiver.direction be the same" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with direction inactive should have result transceiver.direction be the same" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with invalid direction should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track) should have result with sender.track be given track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track) multiple times should create multiple transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with rid longer than 16 characters should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with valid rid value should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with valid sendEncodings should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is null prior to setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="localDescription contains candidates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-candidate-in-sdp.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial connectionState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the connection should set connectionState to closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have transports in connected state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState remains new when not adding remote ice candidates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState transitions to connected via connecting" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire connectionstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.length" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(null)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(undefined)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({})" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: undefined })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [null] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [undefined] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceCandidatePoolSize: toNumberThrows })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="localDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="currentLocalDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingLocalDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="remoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="currentRemoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingRemoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="signalingState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="iceGatheringState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() with null remoteDescription should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() when connection is closed reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with no argument should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with closed connection should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label "foo" should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label null should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label lone surrogate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with ordered false should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with ordered null/undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maxPacketLifeTime 0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maxRetransmits 0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with both maxPacketLifeTime and maxRetransmits undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol "foo" should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol null should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol lone surrogate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 0 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 1 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65534 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 0 and negotiated true should succeed, and set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 1 and negotiated true should succeed, and set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id -1 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65535 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65536 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id -1 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65535 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65536 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long label should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long label (2 byte unicode) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with same label used twice should not throw" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated true and id should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long protocol should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long protocol (2 byte unicode) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maximum length label and protocol should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated false should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated false and id 42 should ignore the id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated true and id not defined should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="Channels created (after setRemoteDescription) should have id assigned" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use (after setRemoteDescription) should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="New datachannel should be in the connecting state after creation (after connection establishment)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating datachannel, should negotiate properly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating datachannel, should negotiate properly when max-bundle is used" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
<testcase purpose="New negotiated datachannel should be in the connecting state after creation (after connection establishment)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_45">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=45</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=45</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating negotiated datachannel, should negotiate properly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_46">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=46</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=46</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating negotiated datachannel, should negotiate properly when max-bundle is used" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_47">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=47</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=47</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() and then setLocalDescription() should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() after connection is closed should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingLocalDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingRemoteDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="currentLocalDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="currentRemoteDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="rolling back an ICE restart when gathering is complete should not result in iceGatheringState changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "complete"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "gathering"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with compulsary RSASSA-PKCS1-v1_5 parameters should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with compulsary ECDSA parameters should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with invalid string algorithm should reject with NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with invalid algorithm dict should reject with NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with valid expires parameter should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with 0 expires parameter should generate expired cert" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with no argument should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats(null) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track not added to connection should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track added via addTrack should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track added via addTransceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track associated with both sender and receiver should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with no argument should return stats report containing peer-connection stats on an empty PC" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() track with stream returns peer-connection and outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() track without stream returns peer-connection and outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() audio outbound-rtp contains all mandatory stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() on track associated with RTCRtpSender should return stats report containing outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() on track associated with RTCRtpReceiver should return stats report containing inbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats(track) should not work if multiple senders have the same track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCStats.timestamp increases with time passing" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial peer connection should have list of zero senders, receivers and transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getTransceivers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting up a connection using helpers and defaults should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-helper-test">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html</test_script_entry>
</description>
</testcase>
<testcase purpose="ICE goes to disconnected if the other side goes away" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState-disconnected.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial iceConnectionState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the connection should set iceConnectionState to closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected or completed connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with audio track should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with audio and video tracks should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="ICE can connect in a recvonly usecase" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Responder ICE connection state behaves as expected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire iceconnectionstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial iceGatheringState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="iceGatheringState should eventually become complete after setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(reoffer) with no new transports should not cause iceGatheringState to change" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with no transports should not cause iceGatheringState to change" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to "checking" and then "complete"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="sRD does not cause ICE gathering state changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="renegotiation that closes all transports should result in ICE gathering state "new"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats succeeds" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Validating stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's ssrc" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's kind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's transportId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's codecId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's packetsReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's packetsLost" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's jitter" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's framesDropped" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's remoteId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's framesDecoded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's nackCount" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's framesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's totalAudioEnergy" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's totalSamplesDuration" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's packetsDiscarded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteInboundRtpStreamStats's localId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteInboundRtpStreamStats's roundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCSentRtpStreamStats's packetsSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCSentRtpStreamStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's remoteId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's framesEncoded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's nackCount" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's framesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteOutboundRtpStreamStats's localId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteOutboundRtpStreamStats's remoteTimestamp" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionStats's dataChannelsOpened" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionStats's dataChannelsClosed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's label" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's protocol" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's dataChannelIdentifier" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's state" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's messagesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's messagesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCMediaSourceStats's trackIdentifier" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCMediaSourceStats's kind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCAudioSourceStats's totalAudioEnergy" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCAudioSourceStats's totalSamplesDuration" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's width" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's height" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's framesPerSecond" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_45">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=45</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=45</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's payloadType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_46">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=46</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=46</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's mimeTypes" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_47">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=47</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=47</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's clockRate" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_48">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=48</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=48</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's channels" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_49">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=49</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=49</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's sdpFmtpLine" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_50">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=50</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=50</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_51">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=51</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=51</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_52">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=52</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=52</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's selectedCandidatePairId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_53">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=53</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=53</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's localCertificateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_54">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=54</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=54</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's remoteCertificateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_55">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=55</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=55</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's transportId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_56">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=56</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=56</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's localCandidateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_57">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=57</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=57</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's remoteCandidateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_58">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=58</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=58</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's state" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_59">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=59</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=59</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's nominated" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_60">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=60</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=60</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_61">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=61</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=61</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_62">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=62</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=62</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's totalRoundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_63">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=63</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=63</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's currentRoundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_64">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=64</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=64</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's address" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_65">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=65</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=65</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's port" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_66">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=66</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=66</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's protocol" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_67">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=67</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=67</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's candidateType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_68">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=68</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=68</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_69">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=69</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=69</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's fingerprintAlgorithm" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_70">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=70</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=70</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's base64Certificate" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_71">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=71</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=71</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel event should fire when new data channel is announced to the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Should be able to send data in a datachannel event handler" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should not be raised when closing the channel in the datachannel event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should be raised when closing the channel in the datachannel event after enqueuing a task" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should not be raised when sending and immediately closing the channel in the datachannel event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiated channel created on remote peer should match the same configuration as local peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiated channel created on remote peer should match the same (default) configuration as local peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated channel should not fire datachannel event on remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Surfacing onicecandidateerror" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-onicecandidateerror.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Creating first data channel should fire negotiationneeded event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="calling createDataChannel twice should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() should fire negotiationneeded event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling addTransceiver() twice should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should not fire if signaling state is not stable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signaling state goes back to stable after setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signaling state goes back to stable after setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signalingstatechange event fires from setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signalingstatechange event fires from setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack should cause negotiationneeded to fire on the caller" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack should cause negotiationneeded to fire on the callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Updating the direction of the transceiver should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setStreams should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding two transceivers, one at a time, results in the expected number of negotiationneeded events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation methods fire signalingstatechange events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire signalingstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="signalingstatechange is the first event to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with m= line of recvonly direction should not trigger track event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() should cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Using offerToReceiveAudio and offerToReceiveVideo should only cause a audio track event to fire, if audio was the only type negotiated" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Using offerToReceiveAudio and offerToReceiveVideo should only cause a video track event to fire, if video was the only type negotiated" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="promiseState helper works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="promiseStateFinal helper works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="pc.getStats must detect InvalidAccessError synchronously always" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer uses operations chain" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiationneeded only fires once operations chain is empty" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Operations queue not vulnerable to recursion by chained negotiationneeded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack when connection is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack on different connection should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack with valid sender should set sender.track to null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack with valid sender should set sender.track to null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection sendrecv should set direction to recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection sendonly should set direction to inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection recvonly should not change direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection inactive should not change direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack on a stopped transceiver should be a no-op" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack on a null track should have no effect" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation needed when returning to stable does not fire too early" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce-onnegotiationneeded.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on a closed peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on initial negotiation" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() fires negotiationneeded after initial negotiation" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() causes fresh ufrags" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() retains dtls transports" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-local-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in initial have-local-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-remote-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() does nothing in initial have-remote-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives remote offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() is satisfied by remote ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() trumps {iceRestart: false}" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives rollback" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on initial negotiation (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() fires negotiationneeded after initial negotiation (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() causes fresh ufrags (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() retains dtls transports (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-local-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in initial have-local-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-remote-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() does nothing in initial have-remote-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives remote offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() is satisfied by remote ICE restart (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() trumps {iceRestart: false} (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives rollback (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer) with m= section should assign mid to corresponding transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should unset transceiver.mid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should only unset transceiver mids associated with current round" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) should remove newly created transceiver from transceiver list" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription should set transceiver inactive if its corresponding m section is rejected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with valid answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting previously generated answer after a call to createOffer should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer) should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription with valid offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription with type offer and null sdp should use lastOffer generated from createOffer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with offer not created by own createOffer() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Creating and setting offer multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting previously generated offer after a call to createAnswer should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation works when there has been a repeated setLocalDescription(offer)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer) should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' goes to 'have-local-offer'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' sets pendingLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' assigns transceiver.mid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' goes to 'stable'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() rejects with InvalidStateError if already closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() never settles if closed while pending" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in a full O/A exchange succeeds" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SRD() rejects with TypeError." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(pranswer) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer) from have-local-pranswer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) from have-local-offer state should reset back to stable state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) after setting answer description should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should ignore invalid sdp content and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should update internal state with a queued tassk, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Switching role from answerer to offerer after going back to stable state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="onsignalingstatechange fires before setLocalDescription resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with valid state and answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription(answer) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription(answer) from have-remote-offer state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with an SDP without a=msid lines triggers ontrack with a default stream." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-nomsid">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with valid offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription multiple times with different offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) from have-local-offer should roll back and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) in stable should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) from have-local-offer is glare-proof" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="repeated sRD(offer) works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="sRD(reoffer) with candidates and without trickle works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose=" Transceivers added by sRD(offer) should not show up until sRD resolves" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) from have-local-offer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(answer) from have-remote-pranswer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() sets the track attribute to a new track." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() sets the track attribute to null." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not set the track synchronously." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() rejects when the peer connection is closed." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not reject when invoked after removeTrack()." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not reject after a subsequent removeTrack()." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) in have-remote-offer state should revert to stable state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) should ignore invalid sdp content and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="local offer created before setRemoteDescription(remote offer) then rollback should still be usable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should remove a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should remove touched transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver created by addtrack" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver without tracks" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="explicit rollback of local offer should remove transceivers and transport" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer to negotiated stable state should enable applying of a local offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a local offer to negotiated stable state should enable applying of a remote offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback a local offer with audio direction change to negotiated stable state and then add video receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="two transceivers with same mids" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="onremovetrack fires during remote rollback" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer with stream changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() with a sender being rolled back does not crash or throw" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Implicit rollback with only a datachannel works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and no stream makes ontrack fire with a track and no stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and a stream makes ontrack fire with a track and a stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="ontrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with two tracks and one stream makes ontrack fire twice with the tracks and shared stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() for an existing stream makes stream.onaddtrack fire." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="stream.onaddtrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and two streams makes ontrack fire with a track and two streams." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="ontrack's receiver matches getReceivers()." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() does not remove the receiver." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="stream.onremovetrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() twice is safe." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with invalid type and invalid SDP should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation should fire signalingsstate events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Switching role from offerer to answerer after going back to stable state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing on setRemoteDescription() neither resolves nor rejects" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing on rollback neither resolves nor rejects" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="addTrack() without setLocalDescription() yields track stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with setLocalDescription() yields track stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="O/A exchange yields outbound RTP stream stats for sending track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="O/A exchange yields inbound RTP stream stats for receiving track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() before offer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() after offer, before answer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() after answer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getStats() contains only outbound-rtp and related stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpReceiver.getStats() contains only inbound-rtp and related stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase> -->
<testcase purpose="RTCPeerConnection.getStats(sendingTrack) is the same as RTCRtpSender.getStats()" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(receivingTrack) is the same as RTCRtpReceiver.getStats()" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(track) throws InvalidAccessError when there are zero senders or receivers for the track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(track) throws InvalidAccessError when there are multiple senders for the track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: creates a transceiver for the sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.sender is associated with the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.receiver has its own track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.receiver's track is muted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver is not associated with an m-section" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver is not stopped" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver's direction is sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver's currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer): transceiver gets associated with an m-section" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer): transceiver.mid matches the offer SDP" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack fires with a track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack's stream.id is the same as stream.id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack fires with a transceiver." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.mid is the same on both ends" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.direction is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.stopped is false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer): transceiver.currentDirection is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer): transceiver.currentDirection is sendonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track): creates a transceiver for the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track): "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track, init): initialize direction to inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track, init): initialize sendEncodings[0].active to false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(0 streams): ontrack fires with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(1 stream): ontrack fires with corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(2 streams): ontrack fires with corresponding two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(0 streams): ontrack fires with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(1 stream): ontrack fires with corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(2 streams): ontrack fires with corresponding two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): creates a transceiver with direction sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.receiver.track.kind == 'audio'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video'): transceiver.receiver.track.kind == 'video'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.sender.track == null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.stopped is false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack reuses reusable transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver does not reuse reusable transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="Can setup two-way call using a single transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the PC stops the transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="Changing transceiver direction to 'sendrecv' makes ontrack fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="transceiver.sender.track does not revert to an old state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="transceiver.direction does not revert to an old state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
<testcase purpose="Signal detector detects track change within reasonable time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-videoDetectorTest">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceErrorEvent constructed from init parameters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceErrorEvent">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with no arguments throws TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: null }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: undefined }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with RTCIceCandidate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with non RTCIceCandidate object throws" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent bubbles and cancelable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.payloadType modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.mimeType modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.clockRate modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.channels modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with new codecs inserted should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.getParameters() should return sendEncodings set by addTransceiver()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with encodings unset should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.rid field should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=17</test_script_entry>
</description>
</testcase> -->
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified headerExtensions should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-headerExtensions">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified rtcp.cname should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.getParameters() should return different transaction IDs for each call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with transaction ID unset should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() twice with the same parameters should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with parameters older than last getParameters() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('dummy') should return null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] getContributingSources() returns an empty list in loopback call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] getContributingSources() returns an empty list in loopback call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="getParameters() with audio receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="getParameters() with video receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Two RTCRtpSenders encoding the same track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-encode-same-track-twice.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('dummy') should return null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on closed connection should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="ReplaceTrack transmits the new track not the old track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() when transceiver is stopped should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams causes streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams can be used to reconstruct a stream with a track on the remote side" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding streams and changing direction causes new streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding streams to an active transceiver causes new streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams() fires InvalidStateError on a closed peer connection." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.transport is null when unconnected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport has a value when connected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Video sender @dtmf is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction should change transceiver.direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction with same direction should have no effect" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction should change transceiver.direction independent of transceiver.currentDirection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with both sender receiver codecs combined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences([]) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with reordered codecs should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with only VP8 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with only H264 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() should allow setting VP8 as first codec" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec clock rate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec channel count should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec parameters should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() modifies the order of audio codecs in createOffer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="A transceiver added and stopped before the initial offer generation should not trigger an offer m-section generation" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="A transceiver added and stopped should not crash when getting receiver's transport" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="During renegotiation, adding and stopping a transceiver should not trigger a renegotiated offer m-section generation" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="A stopped sendonly transceiver should generate an inactive m-section in the offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="A stopped inactive transceiver should generate an inactive m-section in the offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped locally, setting a locally generated answer should still work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped remotely, setting a locally generated answer should still work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped, transceivers, senders and receivers should disappear after offer/answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Locally stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Remotely stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Rollback when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Rollback when removing transceiver does end the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Glare when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Locally stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Remotely stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Rollback when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Rollback when removing transceiver does end the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Glare when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverNoTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithAddTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithDirection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithSetRemoteOfferSending" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithSetRemoteOfferNoSend" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverBadKind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="checkNoMidOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="checkNoMidAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSetDirection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSendrecvWithNoSendTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSendrecvWithTracklessStream" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverNoTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverThenReplaceTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverThenAddTrackPairs" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTrackPairs" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="checkReplaceTrackNullDoesntPreventPairing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="checkRemoveAndReadd" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTrackExistingTransceiverThenRemove" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetLocalOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetRemoteOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetLocalAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterClose" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="checkLocalRollback" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="checkRollbackAndSetRemoteOfferWithDifferentType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateOfferWithReusedMsections" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddIceCandidateToStoppedTransceiver" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="checkBundleTagRejected" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with answer not containing data media should not initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer not containing data media should not initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with answer containing data media should initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer containing data media should initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="SctpTransport objects are created at appropriate times" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-events_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="SctpTransport reaches connected and closed state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-events_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="An unconnected peerconnection must not have maxChannels set" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="maxChannels gets instantiated after connecting" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Determine the local side send limitation (canSendSize) by offering a max-message-size of 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Remote offer SDP missing max-message-size attribute" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="max-message-size with a (non-zero) value provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Renegotiate max-message-size with various values provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="max-message-size with a (non-zero) value larger than canSendSize provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no transceiver should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no track should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no receiver should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="When a=msid is absent, the track should still be associated with a stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be ignored if media-level msid is present" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be parsed if media-level msid is absent" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="stream ids should be found even if msid-semantic is absent" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Applying a remote description with a new msid should trigger firing an event with populated streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Can get stats from a basic WebRTC call." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="getstats">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/getstats.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannel member maxRetransmitTime should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection member getStreamById should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection member updateIce should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpTransceiver member setDirection should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="DataChannel interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCIceCandidate interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCPeerConnection interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCSessionDescription interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call with no data." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="no-media-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/no-media-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call with only data using promises." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="promises-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/promises-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Setup audio call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Inactivate the audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Reactivate the audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Clean-up" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] recvonly transceiver can become sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="recvonly-transceiver-can-become-sendrecv.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] recvonly transceiver can become sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="recvonly-transceiver-can-become-sendrecv.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call without announcing ssrcs." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simplecall-no-ssrcs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simplecall.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="Legacy addStream(): Media stream stats references track stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addStream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
</description>
</testcase> -->
<testcase purpose="createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo should add video line to all subsequent created offers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio set to false should not create a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio should create a "recvonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped "sendrecv" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio set to false with a track should create a "sendonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo set to false should not create a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo should create a "recvonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped "sendrecv" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo set to false with a track should create a "sendonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Rsubsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio and Video should create two "recvonly" transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithStream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveAudio" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveVideo" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveBoth" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Check onaddstream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="onaddstream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Basic simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="basic.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="H264 simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="h264.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Simulcast setParameters active=false stops sending frames" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="setParameters-active.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="VP8 simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="vp8.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer with the maximum set of codecs does not generate invalid payload types" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-payloadTypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
</description>
</testcase>
<testcase purpose="not negotiating BUNDLE creates two separate ice and dtls transports" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="bundle.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="bundles on the first transport and closes the second" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="bundle.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Two way ICE exchange works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding only caller -> callee candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding only callee -> caller candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding callee -> caller candidates from end-of-candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Explicit offer/answer exchange gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates always arrive after setLocalDescription(offer) resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates always arrive after setLocalDescription(answer) resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="tlsVersion is acceptable on data-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="tlsVersion is acceptable on video-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="srtpCipher is acceptable on data-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="srtpCipher is acceptable on video-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Connection fails if one side provides a wrong DTLS fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="dtls-fingerprint-validation">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should accept initial offer with setup=actpass" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="dtls-setup.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-setup.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-setup.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Handover with datachannel reinitiated from new callee completes" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="handover-datachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation of handover initiated at caller works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="handover_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation of handover initiated at callee works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="handover_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should enter connected (or completed) state when candidates are sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should generate offer with a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should enter disconnected state when a failing candidate is sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a ice-ufrag containing a non-ice-char fails" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="ice-ufragpwd_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a ice-pwd containing a non-ice-char fails" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="ice-ufragpwd_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Offer conforms to basic SDP requirements" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="jsep-initial-offer.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Offer description with no mid is accepted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="missing-fields_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Answer description with no mid is accepted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="missing-fields_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with no msid produces a track with a stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with msid:- appid produces a track with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with msid:foo bar produces a stream with id foo" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with two msid produces two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="video rtp timestamps increase by approximately 90000 per second" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-clockrate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Can demux two video tracks with the same payload type on an unbundled connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="rtp-demuxing">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a codec in the range 96-127 works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-payloadtypes_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a codec in the range 35-63 works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-payloadtypes_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial offer should have sensible RTX mappings" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Self-negotiated answer should have sensible RTX parameters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="A remote offer generates sensible RTX references in answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Generated Datachannel SDP uses correct SCTP offer syntax" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="sctp-format">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html</test_script_entry>
</description>
</testcase>
<testcase purpose="rejects a remote offer that only includes SDES and no DTLS fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="sdes-dont-dont-dont">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sdes-dont-dont-dont.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sdes-dont-dont-dont.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() with multiple send encodings should create simulcast answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simulcast-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with multiple send encodings should create simulcast offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simulcast-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Connect audio and video to two independent PeerConnections" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="split.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Unknown media types are rejected with the port set to 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="unknown-mediatypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html</test_script_entry>
</description>
</testcase>
<testcase purpose="H.264 and VP8 should be supported in initial offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="H.264 and VP8 should be negotiated after handshake" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="All H.264 codecs MUST include profile-level-id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
</set>
</capabilities>
<testcase purpose="Check same-origin RTCCertificate serialization" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="RTCCertificate-postMessage">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setConfiguration with different set of certs should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificate should have at least one fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCCertificate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Default bundlePolicy should be balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: undefined }) should have bundlePolicy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'balanced' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'max-compat' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'max-bundle' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial default bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: balanced }) with initial default bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'balanced' }) with initial bundlePolicy balanced should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-compat should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-bundle' }) with initial bundlePolicy max-bundle should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: null }) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ bundlePolicy: 'invalid' }) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-bundle should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial bundlePolicy max-bundle should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-bundlePolicy_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose=" Initialize a new RTCPeerConnection with no iceCandidatePoolSize" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 255" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: -1 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Initialize a new RTCPeerConnection with iceCandidatePoolSize: 256 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 255" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to -1 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 256 (Out Of Range)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceCandidatePoolSize_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default configuration.iceServers of undefined" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - {} should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - {} should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: undefined } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: undefined } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [] } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [] } should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [null] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [null] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [undefined] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [undefined] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - { iceServers: [{}] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - { iceServers: [{}] } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with stun server should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with stun server should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with stun server array should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with stun server array should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server, username, credential should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server, username, credential should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turn server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turn server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and no credentials should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and only username should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with turns server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with turns server and only credential should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with "" url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with "" url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with ["stun:stun1.example.net", ""] url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with ["stun:stun1.example.net", ""] url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with relative url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with relative url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with http url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with http url should throw SyntaxError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceServers_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default iceTransportPolicy all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: undefined }) should have default iceTransportPolicy all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: 'all' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceTransportPolicy: 'relay' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial iceTransportPolicy relay should set new value to all" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with invalid iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with invalid iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with none iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with none iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with null iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with null iceTransportPolicy should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-iceTransportPolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection() should have default rtcpMuxPolicy require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: undefined }) should have default rtcpMuxPolicy require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: 'require' }) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' }) may succeed or throw NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with { rtcpMuxPolicy: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with { rtcpMuxPolicy: null } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(config) - with { rtcpMuxPolicy: 'invalid' } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration(config) - with { rtcpMuxPolicy: 'invalid' } should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ rtcpMuxPolicy: 'negotiate' }) with initial rtcpMuxPolicy require should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({ rtcpMuxPolicy: 'require' }) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setConfiguration({}) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription throws InvalidAccessError when called with an offer without rtcp-mux and rtcpMuxPolicy is set to require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription throws InvalidAccessError when called with an answer without rtcp-mux and rtcpMuxPolicy is set to require" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCConfiguration-rtcpMuxPolicy_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should succeed if tones contains valid DTMF characters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver is stopped" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() after remove and close should reject" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDTMFSender-insertDTMF.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF with duration greater than 6000 should be clamped to 6000" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="RTCDTMFSender-ontonechange-long.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with default duration and intertoneGap should fire tonechange events at the expected time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with explicit duration and intertoneGap should fire tonechange events at the expected time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF('') should not fire any tonechange event, including for '' tone" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with duration less than 40 should be clamped to 40" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with interToneGap less than 30 should be clamped to 30" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF with comma should delay next tonechange event for a constant 2000ms" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Tone change event constructor works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Tone change event with unexpected name should not crash" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDTMFSender-ontonechange.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount initial value should be 0 for both peers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should increase to byte length of encodedunicode string sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should increase to byte length of buffer sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should not decrease immediately after initiating closure" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedAmount should not decrease after closing the peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires after send() is complete" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamount is data.length on send(data)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamount returns the same amount if no more data is" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires only once after multiple consecutive send() calls" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="datachannel bufferedamountlow event fires after each sent message" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount initial value should be 0 for both peers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should increase to byte length of encodedunicode string sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should increase to byte length of buffer sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should not decrease immediately after initiating closure" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedAmount should not decrease after closing the peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires after send() is complete" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamount is data.length on send(data)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamount returns the same amount if no more data is" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires only once after multiple consecutive send() calls" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiated datachannel bufferedamountlow event fires after each sent message" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-bufferedAmount_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Close datachannel causes onclosing and onclose to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Close datachannel causes closing and close event to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error to be called on datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection after datachannel close causes no events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error on many channels, datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Close negotiated datachannel causes onclosing and onclose to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Close negotiated datachannel causes closing and close event to be called" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error to be called on negotiated datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection after negotiated datachannel close causes no events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Close peerconnection causes close event and error on many channels, negotiated datachannel" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-close_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel remains usable after ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel remains usable at each step of an ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-iceRestart_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS client uses odd data channel IDs" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS server uses even data channel IDs" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiation with a specific ID should not work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Odd/even role should not be violated when mixing with negotiated channels" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannel-id_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling send() when data channel is in connecting state should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send simple string and receive as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send unicode string and receive as unicode string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should ignore binaryType and always receive string message as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send an empty string and receive an empty string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send Uint8Array message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send simple string and receive as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send unicode string and receive as unicode string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should ignore binaryType and always receive string message as string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send an empty string and receive an empty string" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send Uint8Array message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated datachannel should be able to send an empty ArrayBuffer message and receive as ArrayBuffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCDataChannel-send_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html?total_num=15&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor without a required argument." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with channel passed as null." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with a channel passed as undefined." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelEvent constructor with full arguments." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDataChannelEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDtlsTransport.prototype.getRemoteCertificates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-getRemoteCertificates">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html</test_script_entry>
</description>
</testcase>
<testcase purpose="DTLS transport goes to connected state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="close() causes the local transport to close immediately" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="close() causes the other end's DTLS transport to close" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCDtlsTransport-state_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor with errorDetail and message" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor's message argument is optional" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor throws TypeError if arguments are missing" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError constructor throws TypeError if the errorDetail is invalid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.name is 'OperationError'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.code is 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.errorDetail is readonly." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCErrorInit.errorDetail is the only required attribute" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sdpLineNumber is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.httpRequestStatusCode is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sctpCauseCode is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.receivedAlert is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is null by default" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is settable by constructor" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCError.sentAlert is readonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCError_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCError.html?total_num=23&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({})" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with manually filled default values" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: null, sdpMLineIndex: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '' })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with valid candidate string only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: 'audio' })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMLineIndex: 0 })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with valid candidate string and sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with nondefault values for all fields" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with nondefault values for all fields, tcp candidate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid sdpMid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCIceCandidate({ ... }) with invalid sdpMLineIndex" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceCandidate-constructor_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="On ICE connected, getStats() contains a connected candidate-pair" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceConnectionState-candidate-pair.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Unconnected iceTransport should have empty remote candidates and selected pair" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCIceTransport">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription and setRemoteDescription are not racy" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-SLD-SRD-timing.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection addTrack does not deadlock." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-add-track-no-deadlock.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added dynamically; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added at PC1; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates are added at PC2; connection should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-connectionSetup_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate is not resolved first if 2x setLocalDescription operations are pending" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate and setLocalDescription are resolved in the correct order, as defined by the operations chain specification" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="onicecandidate fires after resolving setLocalDescription in offerer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="onicecandidate fires after resolving setLocalDescription in answerer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate-timing.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate({"candidate":"","sdpMid":null,"sdpMLineIndex":null}) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate(undefined) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate(null) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate({}) works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Add ICE candidate after setting remote description should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Add ICE candidate with RTCIceCandidate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMid should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMid and RTCIceCandidate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid sdpMLineIndex should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate for first media stream with null usernameFragment should add candidate to first media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding multiple candidates should add candidates to their corresponding media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="addIceCandidate with a candidate and neither sdpMid nor sdpMLineIndex should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with only valid candidate string should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid sdpMid should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid sdpMLineIndex should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="Invalid sdpMLineIndex should be ignored if valid sdpMid is provided" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate for media stream 2 with null usernameFragment should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="Add candidate with invalid candidate string should reject with OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addIceCandidate_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack when pc is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and no stream should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and single stream should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with single track argument and multiple streams should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding the same track multiple times should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender that has not been used to send should reuse the sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender that has been used to send should create new sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack with existing sender with null track, different kind, and recvonly direction should create new sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding more tracks does not generate more candidates if bundled" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling addTrack while sRD(offer) is pending should allow the new remote transceiver to be the same one that addTrack creates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="When addTrack is called while sRD is in progress, and both addTrack and sRD add a transceiver of different media types, the addTrack transceiver should come first, and then the sRD transceiver." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTrack.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with string argument as invalid kind should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio') should return an audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video') should return a video transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with direction sendonly should have result transceiver.direction be the same" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with direction inactive should have result transceiver.direction be the same" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with invalid direction should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track) should have result with sender.track be given track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track) multiple times should create multiple transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with rid longer than 16 characters should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with valid rid value should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with valid sendEncodings should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addTransceiver.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is null prior to setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-canTrickleIceCandidates_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="localDescription contains candidates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-candidate-in-sdp.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial connectionState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the connection should set connectionState to closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have transports in connected state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState remains new when not adding remote ice candidates" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState transitions to connected via connecting" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire connectionstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-connectionState.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.length" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(null)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection(undefined)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({})" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: null })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: undefined })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [null] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ certificates: [undefined] })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCPeerConnection({ iceCandidatePoolSize: toNumberThrows })" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="localDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="currentLocalDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingLocalDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="remoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="currentRemoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingRemoteDescription initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="signalingState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="iceGatheringState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="connectionState initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="canTrickleIceCandidates initial value" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-constructor_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() with null remoteDescription should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() when connection is closed reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createAnswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with no argument should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with closed connection should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label "foo" should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label null should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with label lone surrogate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with ordered false should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with ordered null/undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maxPacketLifeTime 0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maxRetransmits 0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with both maxPacketLifeTime and maxRetransmits undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol "foo" should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol null should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol undefined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with protocol lone surrogate should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 0 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 1 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65534 and negotiated not set should succeed, but not set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 0 and negotiated true should succeed, and set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 1 and negotiated true should succeed, and set the channel's id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id -1 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65535 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65536 and negotiated not set should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id -1 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65535 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with id 65536 should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long label should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long label (2 byte unicode) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with same label used twice should not throw" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated true and id should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long protocol should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with too long protocol (2 byte unicode) should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with maximum length label and protocol should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated false should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated false and id 42 should ignore the id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="createDataChannel with negotiated true and id not defined should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="Channels created (after setRemoteDescription) should have id assigned" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use (after setRemoteDescription) should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) should throw OperationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="New datachannel should be in the connecting state after creation (after connection establishment)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating datachannel, should negotiate properly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating datachannel, should negotiate properly when max-bundle is used" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
<testcase purpose="New negotiated datachannel should be in the connecting state after creation (after connection establishment)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_45">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=45</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=45</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating negotiated datachannel, should negotiate properly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_46">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=46</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=46</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack, then creating negotiated datachannel, should negotiate properly when max-bundle is used" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createDataChannel_47">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=47</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&locator_key=id&value=47</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() and then setLocalDescription() should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() after connection is closed should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingLocalDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="pendingRemoteDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="currentLocalDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="currentRemoteDescription is surfaced at the right time" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-description-attributes-timing.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="rolling back an ICE restart when gathering is complete should not result in iceGatheringState changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "complete"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "gathering"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-explicit-rollback-iceGatheringState_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with compulsary RSASSA-PKCS1-v1_5 parameters should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with compulsary ECDSA parameters should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with invalid string algorithm should reject with NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with invalid algorithm dict should reject with NotSupportedError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with valid expires parameter should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="generateCertificate() with 0 expires parameter should generate expired cert" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-generateCertificate_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with no argument should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats(null) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track not added to connection should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track added via addTrack should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track added via addTransceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with track associated with both sender and receiver should reject with InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() with no argument should return stats report containing peer-connection stats on an empty PC" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() track with stream returns peer-connection and outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() track without stream returns peer-connection and outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() audio outbound-rtp contains all mandatory stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() on track associated with RTCRtpSender should return stats report containing outbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats() on track associated with RTCRtpReceiver should return stats report containing inbound-rtp stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats(track) should not work if multiple senders have the same track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCStats.timestamp increases with time passing" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getStats.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial peer connection should have list of zero senders, receivers and transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-getTransceivers">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting up a connection using helpers and defaults should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-helper-test">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html</test_script_entry>
</description>
</testcase>
<testcase purpose="ICE goes to disconnected if the other side goes away" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState-disconnected.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial iceConnectionState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the connection should set iceConnectionState to closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected or completed connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with audio track should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with audio and video tracks should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="ICE can connect in a recvonly usecase" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="iceConnectionState changes at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Responder ICE connection state behaves as expected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire iceconnectionstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceConnectionState.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial iceGatheringState should be new" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="iceGatheringState should eventually become complete after setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(reoffer) with no new transports should not cause iceGatheringState to change" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with no transports should not cause iceGatheringState to change" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to "checking" and then "complete"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="sRD does not cause ICE gathering state changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="renegotiation that closes all transports should result in ICE gathering state "new"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="connection with one data channel should eventually have connected connection state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-iceGatheringState_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="getStats succeeds" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Validating stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's ssrc" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's kind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's transportId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpStreamStats's codecId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's packetsReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's packetsLost" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's jitter" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCReceivedRtpStreamStats's framesDropped" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's remoteId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's framesDecoded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's nackCount" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's framesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's totalAudioEnergy" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's totalSamplesDuration" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCInboundRtpStreamStats's packetsDiscarded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteInboundRtpStreamStats's localId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteInboundRtpStreamStats's roundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCSentRtpStreamStats's packetsSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCSentRtpStreamStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's remoteId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's framesEncoded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's nackCount" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCOutboundRtpStreamStats's framesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteOutboundRtpStreamStats's localId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRemoteOutboundRtpStreamStats's remoteTimestamp" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionStats's dataChannelsOpened" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionStats's dataChannelsClosed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's label" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's protocol" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's dataChannelIdentifier" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's state" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's messagesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's messagesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannelStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCMediaSourceStats's trackIdentifier" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCMediaSourceStats's kind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCAudioSourceStats's totalAudioEnergy" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCAudioSourceStats's totalSamplesDuration" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's width" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's height" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCVideoSourceStats's framesPerSecond" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_45">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=45</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=45</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's payloadType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_46">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=46</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=46</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's mimeTypes" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_47">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=47</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=47</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's clockRate" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_48">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=48</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=48</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's channels" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_49">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=49</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=49</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCodecStats's sdpFmtpLine" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_50">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=50</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=50</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_51">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=51</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=51</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_52">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=52</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=52</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's selectedCandidatePairId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_53">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=53</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=53</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's localCertificateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_54">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=54</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=54</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCTransportStats's remoteCertificateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_55">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=55</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=55</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's transportId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_56">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=56</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=56</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's localCandidateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_57">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=57</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=57</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's remoteCandidateId" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_58">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=58</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=58</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's state" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_59">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=59</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=59</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's nominated" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_60">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=60</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=60</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's bytesSent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_61">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=61</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=61</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's bytesReceived" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_62">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=62</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=62</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's totalRoundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_63">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=63</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=63</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidatePairStats's currentRoundTripTime" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_64">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=64</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=64</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's address" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_65">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=65</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=65</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's port" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_66">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=66</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=66</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's protocol" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_67">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=67</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=67</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCIceCandidateStats's candidateType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_68">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=68</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=68</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_69">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=69</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=69</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's fingerprintAlgorithm" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_70">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=70</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=70</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCCertificateStats's base64Certificate" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-mandatory-getStats.https_71">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=71</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&locator_key=id&value=71</test_script_entry>
</description>
</testcase>
<testcase purpose="Data channel event should fire when new data channel is announced to the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Should be able to send data in a datachannel event handler" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should not be raised when closing the channel in the datachannel event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should be raised when closing the channel in the datachannel event after enqueuing a task" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Open event should not be raised when sending and immediately closing the channel in the datachannel event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiated channel created on remote peer should match the same configuration as local peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="In-band negotiated channel created on remote peer should match the same (default) configuration as local peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiated channel should not fire datachannel event on remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ondatachannel_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Surfacing onicecandidateerror" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-onicecandidateerror.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Creating first data channel should fire negotiationneeded event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="calling createDataChannel twice should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() should fire negotiationneeded event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling addTransceiver() twice should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should not fire if signaling state is not stable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signaling state goes back to stable after setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signaling state goes back to stable after setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signalingstatechange event fires from setRemoteDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="negotiationneeded event should fire only after signalingstatechange event fires from setLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack should cause negotiationneeded to fire on the caller" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack should cause negotiationneeded to fire on the callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Updating the direction of the transceiver should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setStreams should cause negotiationneeded to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding two transceivers, one at a time, results in the expected number of negotiationneeded events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onnegotiationneeded_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation methods fire signalingstatechange events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing a PeerConnection should not fire signalingstatechange event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="signalingstatechange is the first event to fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-onsignalingstatechanged.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with m= line of recvonly direction should not trigger track event" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() should cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Using offerToReceiveAudio and offerToReceiveVideo should only cause a audio track event to fire, if audio was the only type negotiated" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Using offerToReceiveAudio and offerToReceiveVideo should only cause a video track event to fire, if video was the only type negotiated" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-ontrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="promiseState helper works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="promiseStateFinal helper works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="pc.getStats must detect InvalidAccessError synchronously always" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer uses operations chain" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiationneeded only fires once operations chain is empty" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Operations queue not vulnerable to recursion by chained negotiationneeded" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-operations.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack when connection is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack on different connection should throw InvalidAccessError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver - Calling removeTrack with valid sender should set sender.track to null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack - Calling removeTrack with valid sender should set sender.track to null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection sendrecv should set direction to recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection sendonly should set direction to inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection recvonly should not change direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack with currentDirection inactive should not change direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack on a stopped transceiver should be a no-op" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling removeTrack on a null track should have no effect" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-removeTrack.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation needed when returning to stable does not fire too early" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce-onnegotiationneeded.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on a closed peer connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on initial negotiation" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() fires negotiationneeded after initial negotiation" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() causes fresh ufrags" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() retains dtls transports" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-local-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in initial have-local-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-remote-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() does nothing in initial have-remote-offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives remote offer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() is satisfied by remote ICE restart" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() trumps {iceRestart: false}" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives rollback" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() has no effect on initial negotiation (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() fires negotiationneeded after initial negotiation (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() causes fresh ufrags (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() retains dtls transports (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-local-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in initial have-local-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() works in have-remote-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() does nothing in initial have-remote-offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives remote offer (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() is satisfied by remote ICE restart (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() trumps {iceRestart: false} (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="restartIce() survives rollback (perfect negotiation)" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-restartIce.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer) with m= section should assign mid to corresponding transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should unset transceiver.mid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should only unset transceiver mids associated with current round" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) should remove newly created transceiver from transceiver list" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription should set transceiver inactive if its corresponding m section is rejected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setDescription-transceiver_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with valid answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting previously generated answer after a call to createOffer should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer) should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-answer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription with valid offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription with type offer and null sdp should use lastOffer generated from createOffer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with offer not created by own createOffer() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Creating and setting offer multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Setting previously generated offer after a call to createAnswer should work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation works when there has been a repeated setLocalDescription(offer)" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer) should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-offer_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' goes to 'have-local-offer'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' sets pendingLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'stable' assigns transceiver.mid" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' goes to 'stable'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in 'have-remote-offer' sets transceiver.currentDirection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() rejects with InvalidStateError if already closed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() never settles if closed while pending" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SLD() in a full O/A exchange succeeds" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="Parameterless SRD() rejects with TypeError." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-parameterless.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(pranswer) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer) from have-local-pranswer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-pranswer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) from have-local-offer state should reset back to stable state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) after setting answer description should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should ignore invalid sdp content and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(rollback) should update internal state with a queued tassk, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription-rollback_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Switching role from answerer to offerer after going back to stable state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="onsignalingstatechange fires before setLocalDescription resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setLocalDescription_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with valid state and answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription(answer) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription(answer) from have-remote-offer state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-answer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with an SDP without a=msid lines triggers ontrack with a default stream." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-nomsid">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with valid offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription multiple times with different offer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) from have-local-offer should roll back and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) in stable should update internal state with a queued task, in the right order" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer) from have-local-offer is glare-proof" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="repeated sRD(offer) works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="sRD(reoffer) with candidates and without trickle works" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose=" Transceivers added by sRD(offer) should not show up until sRD resolves" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-offer_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) from have-local-offer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(pranswer) multiple times should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(answer) from have-remote-pranswer state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-pranswer_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() sets the track attribute to a new track." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() sets the track attribute to null." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not set the track synchronously." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() rejects when the peer connection is closed." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not reject when invoked after removeTrack()." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() does not reject after a subsequent removeTrack()." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-replaceTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) in have-remote-offer state should revert to stable state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) from stable state should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(rollback) should ignore invalid sdp content and succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="local offer created before setRemoteDescription(remote offer) then rollback should still be usable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should remove a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should remove touched transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver created by addtrack" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer should keep a transceiver without tracks" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="explicit rollback of local offer should remove transceivers and transport" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer to negotiated stable state should enable applying of a local offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a local offer to negotiated stable state should enable applying of a remote offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback a local offer with audio direction change to negotiated stable state and then add video receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="two transceivers with same mids" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="onremovetrack fires during remote rollback" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="rollback of a remote offer with stream changes" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() with a sender being rolled back does not crash or throw" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="Implicit rollback with only a datachannel works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-rollback_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and no stream makes ontrack fire with a track and no stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and a stream makes ontrack fire with a track and a stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="ontrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with two tracks and one stream makes ontrack fire twice with the tracks and shared stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() for an existing stream makes stream.onaddtrack fire." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="stream.onaddtrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with a track and two streams makes ontrack fire with a track and two streams." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="ontrack's receiver matches getReceivers()." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() does not remove the receiver." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="stream.onremovetrack fires before setRemoteDescription resolves." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="removeTrack() twice is safe." component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription-tracks.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with invalid type and invalid SDP should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation should fire signalingsstate events" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Switching role from offerer to answerer after going back to stable state should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing on setRemoteDescription() neither resolves nor rejects" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing on rollback neither resolves nor rejects" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-setRemoteDescription_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="addTrack() without setLocalDescription() yields track stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack() with setLocalDescription() yields track stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="O/A exchange yields outbound RTP stream stats for sending track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="O/A exchange yields inbound RTP stream stats for receiving track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() before offer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() after offer, before answer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="replaceTrack() after answer: new track attachment stats present" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getStats() contains only outbound-rtp and related stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpReceiver.getStats() contains only inbound-rtp and related stats" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=9</test_script_entry>
</description>
</testcase> -->
<testcase purpose="RTCPeerConnection.getStats(sendingTrack) is the same as RTCRtpSender.getStats()" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(receivingTrack) is the same as RTCRtpReceiver.getStats()" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(track) throws InvalidAccessError when there are zero senders or receivers for the track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection.getStats(track) throws InvalidAccessError when there are multiple senders for the track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-track-stats.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: creates a transceiver for the sender" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.sender is associated with the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.receiver has its own track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver.receiver's track is muted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver is not associated with an m-section" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver is not stopped" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver's direction is sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack: transceiver's currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer): transceiver gets associated with an m-section" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(offer): transceiver.mid matches the offer SDP" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack fires with a track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack's stream.id is the same as stream.id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): ontrack fires with a transceiver." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.mid is the same on both ends" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.direction is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription(offer): transceiver.stopped is false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer): transceiver.currentDirection is recvonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription(answer): transceiver.currentDirection is sendonly" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track): creates a transceiver for the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track): "transceiver == {sender,receiver}"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track, init): initialize direction to inactive" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(track, init): initialize sendEncodings[0].active to false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(0 streams): ontrack fires with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(1 stream): ontrack fires with corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver(2 streams): ontrack fires with corresponding two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(0 streams): ontrack fires with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(1 stream): ontrack fires with corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack(2 streams): ontrack fires with corresponding two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): creates a transceiver with direction sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.receiver.track.kind == 'audio'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('video'): transceiver.receiver.track.kind == 'video'" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.sender.track == null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.currentDirection is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver('audio'): transceiver.stopped is false" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="addTrack reuses reusable transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver does not reuse reusable transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="Can setup two-way call using a single transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="Closing the PC stops the transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="Changing transceiver direction to 'sendrecv' makes ontrack fire" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="transceiver.sender.track does not revert to an old state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_43">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=43</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=43</test_script_entry>
</description>
</testcase>
<testcase purpose="transceiver.direction does not revert to an old state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-transceivers.https_44">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=44</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&locator_key=id&value=44</test_script_entry>
</description>
</testcase>
- <testcase purpose="Signal detector detects track change within reasonable time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-videoDetectorTest">
+ <testcase purpose="Signal detector detects track change within reasonable time" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="manual" priority="P1" id="RTCPeerConnection-videoDetectorTest">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceErrorEvent constructed from init parameters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceErrorEvent">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with no arguments throws TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: null }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: undefined }" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with RTCIceCandidate" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent with non RTCIceCandidate object throws" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnectionIceEvent bubbles and cancelable" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnectionIceEvent-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.payloadType modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.mimeType modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.clockRate modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.channels modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with new codecs inserted should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-codecs_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
- </testcase> -->
+ </testcase>
<testcase purpose="addTransceiver() with undefined sendEncodings should have default encoding parameter with active set to true" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="addTransceiver() with empty list sendEncodings should have default encoding parameter with active set to true" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.getParameters() should return sendEncodings set by addTransceiver()" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with mismatch number of encodings should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with encodings unset should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.rid field should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.active should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.active should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.maxBitrate should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.maxBitrate should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=17</test_script_entry>
</description>
</testcase> -->
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed with RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_32">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=32</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=32</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_33">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=33</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=33</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_34">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=34</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=34</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_35">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=35</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=35</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_36">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=36</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=36</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_37">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=37</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=37</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_38">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=38</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=38</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_39">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=39</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=39</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_40">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=40</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=40</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_41">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=41</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=41</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified encoding.scaleResolutionDownBy should succeed without RTCRtpTransceiverInit" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-encodings_42">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=42</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&locator_key=id&value=42</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified headerExtensions should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-headerExtensions">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified rtcp.cname should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-rtcp_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.getParameters() should return different transaction IDs for each call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="sender.setParameters() with transaction ID unset should reject with TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() twice with the same parameters should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() with parameters older than last getParameters() should reject with InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpParameters-transactionId_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('dummy') should return null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getCapabilities_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] getContributingSources() returns an empty list in loopback call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] getContributingSources() returns an empty list in loopback call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getContributingSources.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="getParameters() with audio receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="getParameters() with video receiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpReceiver-getParameters_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Two RTCRtpSenders encoding the same track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-encode-same-track-twice.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.getCapabilities('dummy') should return null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-getCapabilities_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on closed connection should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
- <testcase purpose="ReplaceTrack transmits the new track not the old track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpSender-replaceTrack.https_8">
+ <testcase purpose="ReplaceTrack transmits the new track not the old track" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="manual" priority="P1" id="RTCRtpSender-replaceTrack.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setParameters() when transceiver is stopped should reject with InvalidStateError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setParameters">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams causes streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams can be used to reconstruct a stream with a track on the remote side" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding streams and changing direction causes new streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding streams to an active transceiver causes new streams to be reported via ontrack on callee" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setStreams() fires InvalidStateError on a closed peer connection." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-setStreams.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender.transport is null when unconnected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport has a value when connected" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy balanced" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy max-bundle" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver.transport at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy max-compat" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender-transport.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Video sender @dtmf is null" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpSender.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction should change transceiver.direction" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction with same direction should have no effect" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setting direction should change transceiver.direction independent of transceiver.currentDirection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-direction_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with both sender receiver codecs combined should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences([]) should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with reordered codecs should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with only VP8 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with only H264 should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() should allow setting VP8 as first codec" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec clock rate should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec channel count should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codec parameters should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="setCodecPreferences() modifies the order of audio codecs in createOffer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-setCodecPreferences_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="A transceiver added and stopped before the initial offer generation should not trigger an offer m-section generation" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="A transceiver added and stopped should not crash when getting receiver's transport" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="During renegotiation, adding and stopping a transceiver should not trigger a renegotiated offer m-section generation" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="A stopped sendonly transceiver should generate an inactive m-section in the offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="A stopped inactive transceiver should generate an inactive m-section in the offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped locally, setting a locally generated answer should still work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped remotely, setting a locally generated answer should still work" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="If a transceiver is stopped, transceivers, senders and receivers should disappear after offer/answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stop_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Locally stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Remotely stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Rollback when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Rollback when removing transceiver does end the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] Glare when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Locally stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Remotely stopping a transceiver ends the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Rollback when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Rollback when removing transceiver does end the track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] Glare when transceiver is not removed does not end track" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-stopping.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverNoTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithAddTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithDirection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithSetRemoteOfferSending" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithSetRemoteOfferNoSend" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverBadKind" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="checkNoMidOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="checkNoMidAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSetDirection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSendrecvWithNoSendTrack" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="checkSendrecvWithTracklessStream" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverNoTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverThenReplaceTrackDoesntPair" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverThenAddTrackPairs" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTrackPairs" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="checkReplaceTrackNullDoesntPreventPairing" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="checkRemoveAndReadd" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_19">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=19</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=19</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTrackExistingTransceiverThenRemove" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_20">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=20</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=20</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_21">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=21</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=21</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetLocalOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_22">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=22</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=22</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetRemoteOffer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_23">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=23</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=23</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_24">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=24</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=24</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterSetLocalAnswer" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_25">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=25</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=25</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterClose" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_26">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=26</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=26</test_script_entry>
</description>
</testcase>
<testcase purpose="checkLocalRollback" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_27">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=27</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=27</test_script_entry>
</description>
</testcase>
<testcase purpose="checkRollbackAndSetRemoteOfferWithDifferentType" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_28">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=28</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=28</test_script_entry>
</description>
</testcase>
<testcase purpose="checkStopAfterCreateOfferWithReusedMsections" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_29">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=29</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=29</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddIceCandidateToStoppedTransceiver" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_30">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=30</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=30</test_script_entry>
</description>
</testcase>
<testcase purpose="checkBundleTagRejected" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCRtpTransceiver.https_31">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=31</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&locator_key=id&value=31</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with answer not containing data media should not initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer not containing data media should not initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription() with answer containing data media should initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setLocalDescription() with answer containing data media should initialize pc.sctp" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="SctpTransport objects are created at appropriate times" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-events_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="SctpTransport reaches connected and closed state" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-events_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="An unconnected peerconnection must not have maxChannels set" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="maxChannels gets instantiated after connecting" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxChannels_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Determine the local side send limitation (canSendSize) by offering a max-message-size of 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Remote offer SDP missing max-message-size attribute" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="max-message-size with a (non-zero) value provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Renegotiate max-message-size with various values provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="max-message-size with a (non-zero) value larger than canSendSize provided by the remote peer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCSctpTransport-maxMessageSize_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no transceiver should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no track should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="new RTCTrackEvent() with no receiver should throw TypeError" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-constructor_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="When a=msid is absent, the track should still be associated with a stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be ignored if media-level msid is present" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be parsed if media-level msid is absent" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="stream ids should be found even if msid-semantic is absent" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Applying a remote description with a new msid should trigger firing an event with populated streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCTrackEvent-fire_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="Can get stats from a basic WebRTC call." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="getstats">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/getstats.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCDataChannel member maxRetransmitTime should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection member getStreamById should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCPeerConnection member updateIce should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="RTCRtpTransceiver member setDirection should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="DataChannel interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCIceCandidate interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCPeerConnection interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="mozRTCSessionDescription interface should not exist" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="historical_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/historical.html?total_num=8&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call with no data." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="no-media-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/no-media-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html</test_script_entry>
</description>
- </testcase>
+ </testcase>
<testcase purpose="Can set up a basic WebRTC call with only data using promises." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="promises-call">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/promises-call.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Setup audio call" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Inactivate the audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Reactivate the audio transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Clean-up" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="receiver-track-live.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="[audio] recvonly transceiver can become sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="recvonly-transceiver-can-become-sendrecv.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="[video] recvonly transceiver can become sendrecv" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="recvonly-transceiver-can-become-sendrecv.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call without announcing ssrcs." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simplecall-no-ssrcs.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Can set up a basic WebRTC call." component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simplecall.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simplecall.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html</test_script_entry>
</description>
</testcase>
<!-- <testcase purpose="Legacy addStream(): Media stream stats references track stats" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-addStream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html</test_script_entry>
</description>
</testcase> -->
<testcase purpose="createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo should add video line to all subsequent created offers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio set to false should not create a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveAudio should create a "recvonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped "recvonly" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped "sendrecv" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio set to false with a track should create a "sendonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_8">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=8</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=8</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio set to false with a "recvonly" transceiver should change the direction to "inactive"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_9">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=9</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=9</test_script_entry>
</description>
</testcase>
<testcase purpose="subsequent offerToReceiveAudio set to false with a track should change the direction to "sendonly"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_10">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=10</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=10</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo set to false should not create a transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_11">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=11</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=11</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with offerToReceiveVideo should create a "recvonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_12">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=12</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=12</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped "recvonly" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_13">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=13</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=13</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped "sendrecv" transceiver exists" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_14">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=14</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=14</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo set to false with a track should create a "sendonly" transceiver" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_15">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=15</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=15</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveVideo set to false with a "recvonly" transceiver should change the direction to "inactive"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_16">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=16</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=16</test_script_entry>
</description>
</testcase>
<testcase purpose="Rsubsequent offerToReceiveVideo set to false with a track should change the direction to "sendonly"" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_17">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=17</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=17</test_script_entry>
</description>
</testcase>
<testcase purpose="offerToReceiveAudio and Video should create two "recvonly" transceivers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCPeerConnection-createOffer-offerToReceive_18">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=18</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&locator_key=id&value=18</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithStream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveAudio" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveVideo" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="checkAddTransceiverWithOfferToReceiveBoth" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="RTCRtpTransceiver-with-OfferToReceive-options.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
- <testcase purpose="Check onaddstream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="onaddstream.https">
+ <testcase purpose="Check onaddstream" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="onaddstream.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Basic simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="basic.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html</test_script_entry>
</description>
</testcase>
- <testcase purpose="H264 simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="h264.https">
+ <testcase purpose="H264 simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="h264.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html</test_script_entry>
</description>
</testcase>
- <testcase purpose="Simulcast setParameters active=false stops sending frames" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" onload_delay="60" priority="P1" id="setParameters-active.https">
+ <testcase purpose="Simulcast setParameters active=false stops sending frames" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="setParameters-active.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="VP8 simulcast setup with two spatial layers" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="vp8.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer with the maximum set of codecs does not generate invalid payload types" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="RTCPeerConnection-payloadTypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html</test_script_entry>
</description>
</testcase>
<testcase purpose="not negotiating BUNDLE creates two separate ice and dtls transports" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="bundle.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="bundles on the first transport and closes the second" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="bundle.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Two way ICE exchange works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding only caller -> callee candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding only callee -> caller candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Adding callee -> caller candidates from end-of-candidates gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="Explicit offer/answer exchange gives a connection" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates always arrive after setLocalDescription(offer) resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Candidates always arrive after setLocalDescription(answer) resolves" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="candidate-exchange.https_7">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&locator_key=id&value=7</test_script_entry>
</description>
</testcase>
<testcase purpose="tlsVersion is acceptable on data-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="tlsVersion is acceptable on video-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="dtlsCipher is acceptable on data-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="dtlsCipher is acceptable on video-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
<testcase purpose="srtpCipher is acceptable on data-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_5">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=5</test_script_entry>
</description>
</testcase>
<testcase purpose="srtpCipher is acceptable on video-only" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="crypto-suite.https_6">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&locator_key=id&value=6</test_script_entry>
</description>
</testcase>
<testcase purpose="Connection fails if one side provides a wrong DTLS fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="dtls-fingerprint-validation">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should accept initial offer with setup=actpass" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="dtls-setup.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/dtls-setup.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-setup.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Handover with datachannel reinitiated from new callee completes" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="handover-datachannel">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation of handover initiated at caller works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="handover_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Negotiation of handover initiated at callee works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="handover_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/handover.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should enter connected (or completed) state when candidates are sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should generate offer with a=ice-options:trickle" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="PC should enter disconnected state when a failing candidate is sent" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="ice-state.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a ice-ufrag containing a non-ice-char fails" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="ice-ufragpwd_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a ice-pwd containing a non-ice-char fails" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="ice-ufragpwd_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Offer conforms to basic SDP requirements" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="jsep-initial-offer.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Offer description with no mid is accepted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="missing-fields_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Answer description with no mid is accepted" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="missing-fields_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with no msid produces a track with a stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with msid:- appid produces a track with no stream" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with msid:foo bar produces a stream with id foo" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Description with two msid produces two streams" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="msid-parse_4">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html?total_num=4&locator_key=id&value=4</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&locator_key=id&value=4</test_script_entry>
</description>
</testcase>
- <testcase purpose="video rtp timestamps increase by approximately 90000 per second" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-clockrate">
+ <testcase purpose="video rtp timestamps increase by approximately 90000 per second" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="rtp-clockrate">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Can demux two video tracks with the same payload type on an unbundled connection" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="rtp-demuxing">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a codec in the range 96-127 works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-payloadtypes_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="setRemoteDescription with a codec in the range 35-63 works" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtp-payloadtypes_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="Initial offer should have sensible RTX mappings" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="Self-negotiated answer should have sensible RTX parameters" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="A remote offer generates sensible RTX references in answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="rtx-codecs.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<testcase purpose="Generated Datachannel SDP uses correct SCTP offer syntax" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="sctp-format">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html</test_script_entry>
</description>
</testcase>
<testcase purpose="rejects a remote offer that only includes SDES and no DTLS fingerprint" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="sdes-dont-dont-dont">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/sdes-dont-dont-dont.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sdes-dont-dont-dont.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createAnswer() with multiple send encodings should create simulcast answer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simulcast-answer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html</test_script_entry>
</description>
</testcase>
<testcase purpose="createOffer() with multiple send encodings should create simulcast offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="simulcast-offer">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Connect audio and video to two independent PeerConnections" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="split.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html</test_script_entry>
</description>
</testcase>
<testcase purpose="Unknown media types are rejected with the port set to 0" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="unknown-mediatypes">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html</test_script_entry>
</description>
</testcase>
<testcase purpose="H.264 and VP8 should be supported in initial offer" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_1">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=1</test_script_entry>
</description>
</testcase>
<testcase purpose="H.264 and VP8 should be negotiated after handshake" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_2">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=2</test_script_entry>
</description>
</testcase>
<testcase purpose="All H.264 codecs MUST include profile-level-id" component="W3C_HTML5 APIs/TBD/WebRTC" execution_type="auto" priority="P1" id="video-codecs.https_3">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&locator_key=id&value=3</test_script_entry>
</description>
</testcase>
<!-- getStats.https.html not supported on Rpi4 iot -->
<testcase purpose="Simulcast getStats results" component="W3C_HTML5 APIs/TBD/WebRTC" onload_delay="60" execution_type="auto" priority="P1" id="getStats.https">
<description>
- <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html</test_script_entry>
+ <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html</test_script_entry>
</description>
</testcase>
</set>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>RTCCertificate persistent Tests</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/get-host-info.sub.js"></script>
-<body>
-<script>
- function findMatchingFingerprint(fingerprints, fingerprint) {
- for (let f of fingerprints) {
- if (f.value == fingerprint.value && f.algorithm == fingerprint.algorithm)
- return true;
- }
- return false;
- }
-
- function with_iframe(url) {
- return new Promise(function(resolve) {
- var frame = document.createElement('iframe');
- frame.src = url;
- frame.onload = function() { resolve(frame); };
- document.body.appendChild(frame);
- });
- }
-
- function testPostMessageCertificate(isCrossOrigin) {
- promise_test(async t => {
- let certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256' });
-
- let url = "resources/RTCCertificate-postMessage-iframe.html";
- if (isCrossOrigin)
- url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/" + url;
-
- let iframe = await with_iframe(url);
-
- let promise = new Promise((resolve, reject) => {
- window.onmessage = (event) => {
- resolve(event.data);
- };
- t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
- });
- iframe.contentWindow.postMessage(certificate, "*");
- let certificate2 = await promise;
-
- const pc1 = new RTCPeerConnection({certificates: [certificate]});
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection({certificates: [certificate2]});
- t.add_cleanup(() => pc2.close());
-
- assert_equals(certificate.expires, certificate2.expires);
- for (let fingerprint of certificate2.getFingerprints())
- assert_true(findMatchingFingerprint(certificate.getFingerprints(), fingerprint), "check fingerprints");
-
- iframe.remove();
- }, "Check " + (isCrossOrigin ? "cross-origin" : "same-origin") + " RTCCertificate serialization");
- }
-
- testPostMessageCertificate(false);
- // testPostMessageCertificate(true);
-
-</script>
-</body>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>RTCCertificate Tests</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the Candidate Recommendation:
- // https://www.w3.org/TR/webrtc/
-
- /*
- 4.2.1. RTCConfiguration Dictionary
- dictionary RTCConfiguration {
- sequence<RTCCertificate> certificates;
- ...
- };
-
- certificates of type sequence<RTCCertificate>
- If this value is absent, then a default set of certificates is
- generated for each RTCPeerConnection instance.
-
- The value for this configuration option cannot change after its
- value is initially selected.
-
- 4.10.2. RTCCertificate Interface
- interface RTCCertificate {
- readonly attribute DOMTimeStamp expires;
- static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
- sequence<RTCDtlsFingerprint> getFingerprints();
- };
-
- 5.5.1 The RTCDtlsFingerprint Dictionary
- dictionary RTCDtlsFingerprint {
- DOMString algorithm;
- DOMString value;
- };
-
- [RFC4572] Comedia over TLS in SDP
- 5. Fingerprint Attribute
- Figure 2. Augmented Backus-Naur Syntax for the Fingerprint Attribute
-
- attribute =/ fingerprint-attribute
-
- fingerprint-attribute = "fingerprint" ":" hash-func SP fingerprint
-
- hash-func = "sha-1" / "sha-224" / "sha-256" /
- "sha-384" / "sha-512" /
- "md5" / "md2" / token
- ; Additional hash functions can only come
- ; from updates to RFC 3279
-
- fingerprint = 2UHEX *(":" 2UHEX)
- ; Each byte in upper-case hex, separated
- ; by colons.
-
- UHEX = DIGIT / %x41-46 ; A-F uppercase
- */
-
- // Helper function to generate certificate with a set of
- // default parameters
- function generateCertificate() {
- return RTCPeerConnection.generateCertificate({
- name: 'ECDSA',
- namedCurve: 'P-256'
- });
- }
-
- // Helper function that takes in an RTCDtlsFingerprint
- // and return an a=fingerprint SDP line
- function fingerprintToSdpLine(fingerprint) {
- return `\r\na=fingerprint:${fingerprint.algorithm} ${fingerprint.value.toUpperCase()}\r\n`;
- }
-
- // Assert that an SDP string has fingerprint line for all the cert's fingerprints
- function assert_sdp_has_cert_fingerprints(sdp, cert) {
- for(const fingerprint of cert.getFingerprints()) {
- const fingerprintLine = fingerprintToSdpLine(fingerprint);
- assert_true(sdp.includes(fingerprintLine),
- 'Expect fingerprint line to be found in SDP');
- }
- }
-
- /*
- 4.3.1. Operation
- When the RTCPeerConnection() constructor is invoked
- 2. If the certificates value in configuration is non-empty,
- check that the expires on each value is in the future.
- If a certificate has expired, throw an InvalidAccessError;
- otherwise, store the certificates. If no certificates value
- was specified, one or more new RTCCertificate instances are
- generated for use with this RTCPeerConnection instance.
- This may happen asynchronously and the value of certificates
- remains undefined for the subsequent steps.
- */
- promise_test(t => {
- return RTCPeerConnection.generateCertificate({
- name: 'ECDSA',
- namedCurve: 'P-256',
- expires: 0
- }).then(cert => {
- assert_less_than_equal(cert.expires, Date.now());
- assert_throws_dom('InvalidAccessError', () =>
- new RTCPeerConnection({ certificates: [cert] }));
- });
- }, 'Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError');
-
- /*
- 4.3.2 Interface Definition
- setConfiguration
- 4. If configuration.certificates is set and the set of
- certificates differs from the ones used when connection
- was constructed, throw an InvalidModificationError.
- */
- promise_test(t => {
- return Promise.all([
- generateCertificate(),
- generateCertificate()
- ]).then(([cert1, cert2]) => {
- const pc = new RTCPeerConnection({
- certificates: [cert1]
- });
-
- // should not throw
- pc.setConfiguration({
- certificates: [cert1]
- });
-
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({
- certificates: [cert2]
- }));
-
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({
- certificates: [cert1, cert2]
- }));
- });
- }, 'Calling setConfiguration with different set of certs should reject with InvalidModificationError');
-
- /*
- 4.10.2. RTCCertificate Interface
- getFingerprints
- Returns the list of certificate fingerprints, one of which is
- computed with the digest algorithm used in the certificate signature.
-
- 5.5.1 The RTCDtlsFingerprint Dictionary
- algorithm of type DOMString
- One of the the hash function algorithms defined in the 'Hash function
- Textual Names' registry, initially specified in [RFC4572] Section 8.
- As noted in [JSEP] Section 5.2.1, the digest algorithm used for the
- fingerprint matches that used in the certificate signature.
-
- value of type DOMString
- The value of the certificate fingerprint in lowercase hex string as
- expressed utilizing the syntax of 'fingerprint' in [ RFC4572] Section 5.
-
- */
- promise_test(t => {
- return generateCertificate()
- .then(cert => {
- assert_idl_attribute(cert, 'getFingerprints');
-
- const fingerprints = cert.getFingerprints();
- assert_true(Array.isArray(fingerprints),
- 'Expect fingerprints to return an array');
-
- assert_greater_than_equal(fingerprints.length, 1,
- 'Expect at last one fingerprint in array');
-
- for(const fingerprint of fingerprints) {
- assert_equals(typeof fingerprint, 'object',
- 'Expect fingerprint to be an object (dictionary)');
-
- // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
- const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512'];
- assert_in_array(fingerprint.algorithm, algorithms,
- 'Expect fingerprint.algorithm to be string of algorithm identifier');
-
- assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value),
- 'Expect fingerprint.value to be lowercase hexadecimal separated by colon');
- }
- });
- }, 'RTCCertificate should have at least one fingerprint');
-
- /*
- 4.3.2 Interface Definition
- createOffer
- The value for certificates in the RTCConfiguration for the
- RTCPeerConnection is used to produce a set of certificate
- fingerprints. These certificate fingerprints are used in the
- construction of SDP and as input to requests for identity
- assertions.
-
- [JSEP]
- 5.2.1. Initial Offers
- For DTLS, all m= sections MUST use all the certificate(s) that have
- been specified for the PeerConnection; as a result, they MUST all
- have the same [I-D.ietf-mmusic-4572-update] fingerprint value(s), or
- these value(s) MUST be session-level attributes.
-
- The following attributes, which are of category IDENTICAL or
- TRANSPORT, MUST appear only in "m=" sections which either have a
- unique address or which are associated with the bundle-tag. (In
- initial offers, this means those "m=" sections which do not contain
- an "a=bundle-only" attribute.)
-
- - An "a=fingerprint" line for each of the endpoint's certificates,
- as specified in [RFC4572], Section 5; the digest algorithm used
- for the fingerprint MUST match that used in the certificate
- signature.
-
- Each m= section which is not bundled into another m= section, MUST
- contain the following attributes (which are of category IDENTICAL or
- TRANSPORT):
-
- - An "a=fingerprint" line for each of the endpoint's certificates,
- as specified in [RFC4572], Section 5; the digest algorithm used
- for the fingerprint MUST match that used in the certificate
- signature.
- */
- promise_test(t => {
- return generateCertificate()
- .then(cert => {
- const pc = new RTCPeerConnection({
- certificates: [cert]
- });
- pc.createDataChannel('test');
-
- return pc.createOffer()
- .then(offer => {
- assert_sdp_has_cert_fingerprints(offer.sdp, cert);
- });
- });
- }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate');
-
- /*
- TODO
-
- 4.10.2. RTCCertificate Interface
- getSupportedAlgorithms
- Returns a sequence providing a representative set of supported
- certificate algorithms. At least one algorithm MUST be returned.
-
- The RTCCertificate object can be stored and retrieved from persistent
- storage by an application. When a user agent is required to obtain a
- structured clone [HTML5] of a RTCCertificate object, it performs the
- following steps:
- 1. Let input and memory be the corresponding inputs defined by the
- internal structured cloning algorithm, where input represents a
- RTCCertificate object to be cloned.
- 2. Let output be a newly constructed RTCCertificate object.
- 3. Copy the value of the expires attribute from input to output.
- 4. Let the [[certificate]] internal slot of output be set to the
- result of invoking the internal structured clone algorithm
- recursively on the corresponding internal slots of input, with
- the slot contents as the new " input" argument and memory as
- the new " memory" argument.
- 5. Let the [[handle]] internal slot of output refer to the same
- private keying material represented by the [[handle]] internal
- slot of input.
- */
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCConfiguration bundlePolicy</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- ...
- RTCConfiguration getConfiguration();
- void setConfiguration(RTCConfiguration configuration);
- };
-
- 4.2.1. RTCConfiguration Dictionary
- dictionary RTCConfiguration {
- RTCBundlePolicy bundlePolicy = "balanced";
- ...
- };
-
- 4.2.6. RTCBundlePolicy Enum
- enum RTCBundlePolicy {
- "balanced",
- "max-compat",
- "max-bundle"
- };
- */
-
- test(() => {
- const pc = new RTCPeerConnection();
- assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
- }, 'Default bundlePolicy should be balanced');
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: undefined });
- assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
- }, `new RTCPeerConnection({ bundlePolicy: undefined }) should have bundlePolicy balanced`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
- assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
- }, `new RTCPeerConnection({ bundlePolicy: 'balanced' }) should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-compat' });
- assert_equals(pc.getConfiguration().bundlePolicy, 'max-compat');
- }, `new RTCPeerConnection({ bundlePolicy: 'max-compat' }) should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
- assert_equals(pc.getConfiguration().bundlePolicy, 'max-bundle');
- }, `new RTCPeerConnection({ bundlePolicy: 'max-bundle' }) should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection();
- pc.setConfiguration({});
- }, 'setConfiguration({}) with initial default bundlePolicy balanced should succeed');
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
- pc.setConfiguration({});
- }, 'setConfiguration({}) with initial bundlePolicy balanced should succeed');
-
- test(() => {
- const pc = new RTCPeerConnection();
- pc.setConfiguration({ bundlePolicy: 'balanced' });
- }, 'setConfiguration({ bundlePolicy: balanced }) with initial default bundlePolicy balanced should succeed');
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
- pc.setConfiguration({ bundlePolicy: 'balanced' });
- }, `setConfiguration({ bundlePolicy: 'balanced' }) with initial bundlePolicy balanced should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-compat' });
- pc.setConfiguration({ bundlePolicy: 'max-compat' });
- }, `setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-compat should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
- pc.setConfiguration({ bundlePolicy: 'max-bundle' });
- }, `setConfiguration({ bundlePolicy: 'max-bundle' }) with initial bundlePolicy max-bundle should succeed`);
-
- test(() => {
- assert_throws_js(TypeError, () =>
- new RTCPeerConnection({ bundlePolicy: null }));
- }, `new RTCPeerConnection({ bundlePolicy: null }) should throw TypeError`);
-
- test(() => {
- assert_throws_js(TypeError, () =>
- new RTCPeerConnection({ bundlePolicy: 'invalid' }));
- }, `new RTCPeerConnection({ bundlePolicy: 'invalid' }) should throw TypeError`);
-
- /*
- 4.3.2. Interface Definition
- To set a configuration
- 5. If configuration.bundlePolicy is set and its value differs from the
- connection's bundle policy, throw an InvalidModificationError.
- */
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
- assert_idl_attribute(pc, 'setConfiguration');
-
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({ bundlePolicy: 'max-compat' }));
- }, `setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-bundle should throw InvalidModificationError`);
-
- test(() => {
- const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
- assert_idl_attribute(pc, 'setConfiguration');
-
- // the default value for bundlePolicy is balanced
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({}));
- }, `setConfiguration({}) with initial bundlePolicy max-bundle should throw InvalidModificationError`);
-
- /*
- Coverage Report
- Tested 2
- Total 2
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<!--
-4.2.1 RTCConfiguration Dictionary
-
- The RTCConfiguration defines a set of parameters to configure how the peer to peer communication established via RTCPeerConnection is established or re-established.
-
- ...
-
- iceCandidatePoolSize of type octet, defaulting to 0
- Size of the prefetched ICE pool as defined in [JSEP] (section 3.5.4. and section 4.1.1.).
--->
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-
-/*
-
-dictionary RTCConfiguration {
- ...
- [EnforceRange]
- octet iceCandidatePoolSize = 0;
-};
-
-... of type octet
-*/
-test(() => {
- const pc = new RTCPeerConnection();
- assert_idl_attribute(pc, "getConfiguration");
- assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
-}, "Initialize a new RTCPeerConnection with no iceCandidatePoolSize");
-
-test(() => {
- const pc = new RTCPeerConnection({
- iceCandidatePoolSize: 0
- });
- assert_idl_attribute(pc, "getConfiguration");
- assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
-}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 0");
-
-test(() => {
- const pc = new RTCPeerConnection({
- iceCandidatePoolSize: 255
- });
- assert_idl_attribute(pc, "getConfiguration");
- assert_equals(pc.getConfiguration().iceCandidatePoolSize, 255);
-}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 255");
-
-test(() => {
- assert_throws_js(TypeError, () => {
- new RTCPeerConnection({
- iceCandidatePoolSize: -1
- });
- });
-}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: -1 (Out Of Range)");
-
-test(() => {
- assert_throws_js(TypeError, () => {
- new RTCPeerConnection({
- iceCandidatePoolSize: 256
- });
- });
-}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 256 (Out Of Range)");
-
-
-/*
-Reconfiguration
-*/
-
-test(() => {
- const pc = new RTCPeerConnection();
- assert_idl_attribute(pc, "getConfiguration");
- assert_idl_attribute(pc, "setConfiguration");
- pc.setConfiguration({
- iceCandidatePoolSize: 0
- });
- assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
-}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 0");
-
-test(() => {
- const pc = new RTCPeerConnection();
- assert_idl_attribute(pc, "getConfiguration");
- assert_idl_attribute(pc, "setConfiguration");
- pc.setConfiguration({
- iceCandidatePoolSize: 255
- });
- assert_equals(pc.getConfiguration().iceCandidatePoolSize, 255);
-}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 255");
-
-/*
-The following tests include an explicit assertion for the existence of a
-setConfiguration function to prevent the assert_throws_js from catching the
-TypeError object that will be thrown when attempting to call the
-non-existent setConfiguration method (in cases where it has not yet
-been implemented). Without this check, these tests will pass incorrectly.
-*/
-
-test(() => {
- const pc = new RTCPeerConnection();
- assert_equals(typeof pc.setConfiguration, "function", "RTCPeerConnection.prototype.setConfiguration is not implemented");
- assert_throws_js(TypeError, () => {
- pc.setConfiguration({
- iceCandidatePoolSize: -1
- });
- });
-}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to -1 (Out Of Range)");
-
-test(() => {
- const pc = new RTCPeerConnection();
- assert_equals(typeof pc.setConfiguration, "function", "RTCPeerConnection.prototype.setConfiguration is not implemented");
- assert_throws_js(TypeError, () => {
- pc.setConfiguration({
- iceCandidatePoolSize: 256
- });
- });
-}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 256 (Out Of Range)");
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCConfiguration iceServers</title>
-<script src='../resources/testharness.js'></script>
-<script src='../resources/testharnessreport.js'></script>
-<script src='support/RTCConfiguration-helper.js'></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor's draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- // The following helper function is called from
- // RTCConfiguration-helper.js:
- // config_test
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- ...
- };
- 4.2.1. RTCConfiguration Dictionary
- dictionary RTCConfiguration {
- sequence<RTCIceServer> iceServers = [];
- ...
- };
- 4.2.4. RTCIceServer Dictionary
- dictionary RTCIceServer {
- required (DOMString or sequence<DOMString>) urls;
- DOMString username;
- DOMString credential;
- };
- */
-
- test(() => {
- const pc = new RTCPeerConnection();
- assert_array_equals(pc.getConfiguration().iceServers, []);
- }, 'new RTCPeerConnection() should have default configuration.iceServers of undefined');
-
- config_test(makePc => {
- makePc({});
- }, '{} should succeed');
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceServers: null }));
- }, '{ iceServers: null } should throw TypeError');
-
- config_test(makePc => {
- const pc = makePc({ iceServers: undefined });
- assert_array_equals(pc.getConfiguration().iceServers, []);
- }, '{ iceServers: undefined } should succeed');
-
- config_test(makePc => {
- const pc = makePc({ iceServers: [] });
- assert_array_equals(pc.getConfiguration().iceServers, []);
- }, '{ iceServers: [] } should succeed');
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceServers: [null] }));
- }, '{ iceServers: [null] } should throw TypeError');
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceServers: [undefined] }));
- }, '{ iceServers: [undefined] } should throw TypeError');
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceServers: [{}] }));
- }, '{ iceServers: [{}] } should throw TypeError');
-
- config_test(makePc => {
- const pc = makePc({ iceServers: [{
- urls: 'stun:stun1.example.net'
- }] });
-
- const { iceServers } = pc.getConfiguration();
- assert_equals(iceServers.length, 1);
-
- const server = iceServers[0];
- assert_array_equals(server.urls, ['stun:stun1.example.net']);
-
- }, `with stun server should succeed`);
-
- config_test(makePc => {
- const pc = makePc({ iceServers: [{
- urls: ['stun:stun1.example.net']
- }] });
-
- const { iceServers } = pc.getConfiguration();
- assert_equals(iceServers.length, 1);
-
- const server = iceServers[0];
- assert_array_equals(server.urls, ['stun:stun1.example.net']);
-
- }, `with stun server array should succeed`);
-
- config_test(makePc => {
- const pc = makePc({ iceServers: [{
- urls: 'turn:turn.example.org',
- username: 'user',
- credential: 'cred'
- }] });
-
- const { iceServers } = pc.getConfiguration();
- assert_equals(iceServers.length, 1);
-
- const server = iceServers[0];
- assert_array_equals(server.urls, ['turn:turn.example.org']);
- assert_equals(server.username, 'user');
- assert_equals(server.credential, 'cred');
-
- }, `with turn server, username, credential should succeed`);
-
- /*
- 4.3.2. To set a configuration
- 11.4. If scheme name is turn or turns, and either of server.username or
- server.credential are omitted, then throw an InvalidAccessError.
- */
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turn:turn.example.net'
- }] }));
- }, 'with turn server and no credentials should throw InvalidAccessError');
-
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turn:turn.example.net',
- username: 'user'
- }] }));
- }, 'with turn server and only username should throw InvalidAccessError');
-
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turn:turn.example.net',
- credential: 'cred'
- }] }));
- }, 'with turn server and only credential should throw InvalidAccessError');
-
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turns:turn.example.net'
- }] }));
- }, 'with turns server and no credentials should throw InvalidAccessError');
-
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turns:turn.example.net',
- username: 'user'
- }] }));
- }, 'with turns server and only username should throw InvalidAccessError');
-
- config_test(makePc => {
- assert_throws_dom('InvalidAccessError', () =>
- makePc({ iceServers: [{
- urls: 'turns:turn.example.net',
- credential: 'cred'
- }] }));
- }, 'with turns server and only credential should throw InvalidAccessError');
-
- /*
- 4.3.2. To set a configuration
- 11.3. For each url in server.urls parse url and obtain scheme name.
- - If the scheme name is not implemented by the browser, throw a SyntaxError.
- - or if parsing based on the syntax defined in [ RFC7064] and [RFC7065] fails,
- throw a SyntaxError.
- [RFC7064] URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol
- 3.1. URI Scheme Syntax
- stunURI = scheme ":" host [ ":" port ]
- scheme = "stun" / "stuns"
- [RFC7065] Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers
- 3.1. URI Scheme Syntax
- turnURI = scheme ":" host [ ":" port ]
- [ "?transport=" transport ]
- scheme = "turn" / "turns"
- transport = "udp" / "tcp" / transport-ext
- transport-ext = 1*unreserved
- */
- config_test(makePc => {
- assert_throws_dom("SyntaxError", () =>
- makePc({ iceServers: [{
- urls: ''
- }] }));
- }, 'with "" url should throw SyntaxError');
-
- config_test(makePc => {
- assert_throws_dom("SyntaxError", () =>
- makePc({ iceServers: [{
- urls: ['stun:stun1.example.net', '']
- }] }));
- }, 'with ["stun:stun1.example.net", ""] url should throw SyntaxError');
-
- config_test(makePc => {
- assert_throws_dom("SyntaxError", () =>
- makePc({ iceServers: [{
- urls: 'relative-url'
- }] }));
- }, 'with relative url should throw SyntaxError');
-
- config_test(makePc => {
- assert_throws_dom("SyntaxError", () =>
- makePc({ iceServers: [{
- urls: 'http://example.com'
- }] }));
- }, 'with http url should throw SyntaxError');
-
-</script>
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<meta name="timeout" content="long">
-<title>RTCConfiguration iceTransportPolicy</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCConfiguration-helper.js"></script>
-<script src="support/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 function is called from RTCConfiguration-helper.js:
- // config_test
-
- /*
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- RTCConfiguration getConfiguration();
- void setConfiguration(RTCConfiguration configuration);
- ...
- };
-
- dictionary RTCConfiguration {
- sequence<RTCIceServer> iceServers;
- RTCIceTransportPolicy iceTransportPolicy = "all";
- };
-
- enum RTCIceTransportPolicy {
- "relay",
- "all"
- };
- */
-
- test(() => {
- const pc = new RTCPeerConnection();
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
- }, `new RTCPeerConnection() should have default iceTransportPolicy all`);
-
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: undefined });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
- }, `new RTCPeerConnection({ iceTransportPolicy: undefined }) should have default iceTransportPolicy all`);
-
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: 'all' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
- }, `new RTCPeerConnection({ iceTransportPolicy: 'all' }) should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
- }, `new RTCPeerConnection({ iceTransportPolicy: 'relay' }) should succeed`);
-
- /*
- 4.3.2. Set a configuration
- 8. Set the ICE Agent's ICE transports setting to the value of
- configuration.iceTransportPolicy. As defined in [JSEP] (section 4.1.16.),
- if the new ICE transports setting changes the existing setting, no action
- will be taken until the next gathering phase. If a script wants this to
- happen immediately, it should do an ICE restart.
- */
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: 'all' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
-
- pc.setConfiguration({ iceTransportPolicy: 'relay' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
- }, `setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
-
- pc.setConfiguration({ iceTransportPolicy: 'all' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
- }, `setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
-
- // default value for iceTransportPolicy is all
- pc.setConfiguration({});
- assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
- }, `setConfiguration({}) with initial iceTransportPolicy relay should set new value to all`);
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceTransportPolicy: 'invalid' }));
- }, `with invalid iceTransportPolicy should throw TypeError`);
-
- // "none" is in Blink and Gecko's IDL, but not in the spec.
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceTransportPolicy: 'none' }));
- }, `with none iceTransportPolicy should throw TypeError`);
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ iceTransportPolicy: null }));
- }, `with null iceTransportPolicy should throw TypeError`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<title>RTCConfiguration rtcpMuxPolicy</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCConfiguration-helper.js"></script>
-<script src="support/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 function is called from RTCConfiguration-helper.js:
- // config_test
-
- /*
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- RTCConfiguration getConfiguration();
- void setConfiguration(RTCConfiguration configuration);
- ...
- };
-
- dictionary RTCConfiguration {
- RTCRtcpMuxPolicy rtcpMuxPolicy = "require";
- ...
- };
-
- enum RTCRtcpMuxPolicy {
- "negotiate",
- "require"
- };
- */
-
- test(() => {
- const pc = new RTCPeerConnection();
- assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
- }, `new RTCPeerConnection() should have default rtcpMuxPolicy require`);
-
- test(() => {
- const pc = new RTCPeerConnection({ rtcpMuxPolicy: undefined });
- assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
- }, `new RTCPeerConnection({ rtcpMuxPolicy: undefined }) should have default rtcpMuxPolicy require`);
-
- test(() => {
- const pc = new RTCPeerConnection({ rtcpMuxPolicy: 'require' });
- assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
- }, `new RTCPeerConnection({ rtcpMuxPolicy: 'require' }) should succeed`);
-
- /*
- 4.3.1.1. Constructor
- 3. If configuration.rtcpMuxPolicy is negotiate, and the user agent does not
- implement non-muxed RTCP, throw a NotSupportedError.
- */
- test(() => {
- let pc;
- try {
- pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
- } catch(err) {
- // NotSupportedError is a DOMException with code 9
- if(err.code === 9 && err.name === 'NotSupportedError') {
- // ignore error and pass test if negotiate is not supported
- return;
- } else {
- throw err;
- }
- }
-
- assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'negotiate');
-
- }, `new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' }) may succeed or throw NotSupportedError`);
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ rtcpMuxPolicy: null }));
- }, `with { rtcpMuxPolicy: null } should throw TypeError`);
-
- config_test(makePc => {
- assert_throws_js(TypeError, () =>
- makePc({ rtcpMuxPolicy: 'invalid' }));
- }, `with { rtcpMuxPolicy: 'invalid' } should throw TypeError`);
-
- /*
- 4.3.2. Set a configuration
- 6. If configuration.rtcpMuxPolicy is set and its value differs from the
- connection's rtcpMux policy, throw an InvalidModificationError.
- */
-
- test(() => {
- const pc = new RTCPeerConnection({ rtcpMuxPolicy: 'require' });
- assert_idl_attribute(pc, 'setConfiguration');
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({ rtcpMuxPolicy: 'negotiate' }));
-
- }, `setConfiguration({ rtcpMuxPolicy: 'negotiate' }) with initial rtcpMuxPolicy require should throw InvalidModificationError`);
-
- test(() => {
- let pc;
- try {
- pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
- } catch(err) {
- // NotSupportedError is a DOMException with code 9
- if(err.code === 9 && err.name === 'NotSupportedError') {
- // ignore error and pass test if negotiate is not supported
- return;
- } else {
- throw err;
- }
- }
-
- assert_idl_attribute(pc, 'setConfiguration');
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({ rtcpMuxPolicy: 'require' }));
-
- }, `setConfiguration({ rtcpMuxPolicy: 'require' }) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError`);
-
- test(() => {
- let pc;
- try {
- pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
- } catch(err) {
- // NotSupportedError is a DOMException with code 9
- if(err.code === 9 && err.name === 'NotSupportedError') {
- // ignore error and pass test if negotiate is not supported
- return;
- } else {
- throw err;
- }
- }
-
- assert_idl_attribute(pc, 'setConfiguration');
- // default value for rtcpMuxPolicy is require
- assert_throws_dom('InvalidModificationError', () =>
- pc.setConfiguration({}));
-
- }, `setConfiguration({}) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError`);
-
- /*
- Coverage Report
-
- Tested 2
- Total 2
- */
- const FINGERPRINT_SHA256 = '00:00:00:00:00:00:00:00:00:00:00:00:00' +
- ':00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00';
- const ICEUFRAG = 'someufrag';
- const ICEPWD = 'somelongpwdwithenoughrandomness';
-
- promise_test(async t => {
- // audio-only SDP offer without BUNDLE and rtcp-mux.
- const sdp = 'v=0\r\n' +
- 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
- 's=-\r\n' +
- 't=0 0\r\n' +
- 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
- 'c=IN IP4 0.0.0.0\r\n' +
- 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
- 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
- 'a=ice-pwd:' + ICEPWD + '\r\n' +
- 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
- 'a=setup:actpass\r\n' +
- 'a=mid:audio1\r\n' +
- 'a=sendonly\r\n' +
- 'a=rtcp-rsize\r\n' +
- 'a=rtpmap:111 opus/48000/2\r\n';
- const pc = new RTCPeerConnection({rtcpMuxPolicy: 'require'});
- t.add_cleanup(() => pc.close());
-
- return promise_rejects_dom(t, 'InvalidAccessError', pc.setRemoteDescription({type: 'offer', sdp}));
- }, 'setRemoteDescription throws InvalidAccessError when called with an offer without rtcp-mux and rtcpMuxPolicy is set to require');
-
- promise_test(async t => {
- // audio-only SDP answer without BUNDLE and rtcp-mux.
- // Also omitting a=mid in order to avoid parsing it from the offer as this needs to match.
- const sdp = 'v=0\r\n' +
- 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
- 's=-\r\n' +
- 't=0 0\r\n' +
- 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
- 'c=IN IP4 0.0.0.0\r\n' +
- 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
- 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
- 'a=ice-pwd:' + ICEPWD + '\r\n' +
- 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
- 'a=setup:active\r\n' +
- 'a=sendonly\r\n' +
- 'a=rtcp-rsize\r\n' +
- 'a=rtpmap:111 opus/48000/2\r\n';
- const pc = new RTCPeerConnection({rtcpMuxPolicy: 'require'});
- t.add_cleanup(() => pc.close());
-
- const offer = await generateAudioReceiveOnlyOffer(pc);
- await pc.setLocalDescription(offer);
- return promise_rejects_dom(t, 'InvalidAccessError', pc.setRemoteDescription({type: 'answer', sdp}));
- }, 'setRemoteDescription throws InvalidAccessError when called with an answer without rtcp-mux and rtcpMuxPolicy is set to require');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCDTMFSender.prototype.insertDTMF</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/RTCDTMFSender-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
- // generateAnswer
-
- // The following helper functions are called from RTCDTMFSender-helper.js
- // createDtmfSender
- // test_tone_change_events
- // getTransceiver
-
- /*
- 7. Peer-to-peer DTMF
- partial interface RTCRtpSender {
- readonly attribute RTCDTMFSender? dtmf;
- };
-
- interface RTCDTMFSender : EventTarget {
- void insertDTMF(DOMString tones,
- optional unsigned long duration = 100,
- optional unsigned long interToneGap = 70);
- attribute EventHandler ontonechange;
- readonly attribute DOMString toneBuffer;
- };
- */
-
- /*
- 7.2. insertDTMF
- The tones parameter is treated as a series of characters.
-
- The characters 0 through 9, A through D, #, and * generate the associated
- DTMF tones.
-
- The characters a to d MUST be normalized to uppercase on entry and are
- equivalent to A to D.
-
- As noted in [RTCWEB-AUDIO] Section 3, support for the characters 0 through 9,
- A through D, #, and * are required.
-
- The character ',' MUST be supported, and indicates a delay of 2 seconds
- before processing the next character in the tones parameter.
-
- All other characters (and only those other characters) MUST be considered
- unrecognized.
- */
- promise_test(async t => {
- const dtmfSender = await createDtmfSender();
- dtmfSender.insertDTMF('');
- dtmfSender.insertDTMF('012345689');
- dtmfSender.insertDTMF('ABCD');
- dtmfSender.insertDTMF('abcd');
- dtmfSender.insertDTMF('#*');
- dtmfSender.insertDTMF(',');
- dtmfSender.insertDTMF('0123456789ABCDabcd#*,');
- }, 'insertDTMF() should succeed if tones contains valid DTMF characters');
-
-
- /*
- 7.2. insertDTMF
- 6. If tones contains any unrecognized characters, throw an
- InvalidCharacterError.
- */
- promise_test(async t => {
- const dtmfSender = await createDtmfSender();
- assert_throws_dom('InvalidCharacterError', () =>
- // 'F' is invalid
- dtmfSender.insertDTMF('123FFABC'));
-
- assert_throws_dom('InvalidCharacterError', () =>
- // 'E' is invalid
- dtmfSender.insertDTMF('E'));
-
- assert_throws_dom('InvalidCharacterError', () =>
- // ' ' is invalid
- dtmfSender.insertDTMF('# *'));
- }, 'insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters');
-
- /*
- 7.2. insertDTMF
- 3. If transceiver.stopped is true, throw an InvalidStateError.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const dtmfSender = transceiver.sender.dtmf;
-
- transceiver.stop();
- assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
-
- }, 'insertDTMF() should throw InvalidStateError if transceiver is stopped');
-
- /*
- 7.2. insertDTMF
- 4. If transceiver.currentDirection is recvonly or inactive, throw an InvalidStateError.
- */
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const transceiver =
- caller.addTransceiver('audio', { direction: 'recvonly' });
- const dtmfSender = transceiver.sender.dtmf;
-
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- callee.addTrack(track, stream);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'recvonly');
- assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
- }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver =
- pc.addTransceiver('audio', { direction: 'inactive' });
- const dtmfSender = transceiver.sender.dtmf;
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'inactive');
- assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
- }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive');
-
- /*
- 7.2. insertDTMF
- The characters a to d MUST be normalized to uppercase on entry and are
- equivalent to A to D.
-
- 7. Set the object's toneBuffer attribute to tones.
- */
- promise_test(async t => {
- const dtmfSender = await createDtmfSender();
- dtmfSender.insertDTMF('123');
- assert_equals(dtmfSender.toneBuffer, '123');
-
- dtmfSender.insertDTMF('ABC');
- assert_equals(dtmfSender.toneBuffer, 'ABC');
-
- dtmfSender.insertDTMF('bcd');
- assert_equals(dtmfSender.toneBuffer, 'BCD');
- }, 'insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- const sender = pc.addTrack(track, mediaStream);
- await pc.setLocalDescription(await pc.createOffer());
- const dtmfSender = sender.dtmf;
- pc.removeTrack(sender);
- pc.close();
- assert_throws_dom('InvalidStateError', () =>
- dtmfSender.insertDTMF('123'));
- }, 'insertDTMF() after remove and close should reject');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCDTMFSender.prototype.ontonechange (Long Timeout)</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/RTCDTMFSender-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 RTCDTMFSender-helper.js
- // test_tone_change_events
-
- /*
- 7. Peer-to-peer DTMF
- partial interface RTCRtpSender {
- readonly attribute RTCDTMFSender? dtmf;
- };
-
- interface RTCDTMFSender : EventTarget {
- void insertDTMF(DOMString tones,
- optional unsigned long duration = 100,
- optional unsigned long interToneGap = 70);
- attribute EventHandler ontonechange;
- readonly attribute DOMString toneBuffer;
- };
-
- [Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
- interface RTCDTMFToneChangeEvent : Event {
- readonly attribute DOMString tone;
- };
- */
-
- /*
- 7.2. insertDTMF
- 8. If the value of the duration parameter is less than 40, set it to 40.
- If, on the other hand, the value is greater than 6000, set it to 6000.
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('A', 8000, 70);
- }, [
- ['A', '', 0],
- ['', '', 6070]
- ],'insertDTMF with duration greater than 6000 should be clamped to 6000');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCDTMFSender.prototype.ontonechange</title>
-<meta name="timeout" content="long">
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/RTCDTMFSender-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
- // generateAnswer
-
- // The following helper functions are called from RTCDTMFSender-helper.js
- // test_tone_change_events
- // getTransceiver
-
- /*
- 7. Peer-to-peer DTMF
- partial interface RTCRtpSender {
- readonly attribute RTCDTMFSender? dtmf;
- };
-
- interface RTCDTMFSender : EventTarget {
- void insertDTMF(DOMString tones,
- optional unsigned long duration = 100,
- optional unsigned long interToneGap = 70);
- attribute EventHandler ontonechange;
- readonly attribute DOMString toneBuffer;
- };
-
- [Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
- interface RTCDTMFToneChangeEvent : Event {
- readonly attribute DOMString tone;
- };
- */
-
- /*
- 7.2. insertDTMF
- 11. If a Playout task is scheduled to be run; abort these steps; otherwise queue
- a task that runs the following steps (Playout task):
- 3. If toneBuffer is an empty string, fire an event named tonechange with an
- empty string at the RTCDTMFSender object and abort these steps.
- 4. Remove the first character from toneBuffer and let that character be tone.
- 6. Queue a task to be executed in duration + interToneGap ms from now that
- runs the steps labelled Playout task.
- 7. Fire an event named tonechange with a string consisting of tone at the
- RTCDTMFSender object.
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('123');
- }, [
- ['1', '23', 0],
- ['2', '3', 170],
- ['3', '', 170],
- ['', '', 170]
- ], 'insertDTMF() with default duration and intertoneGap should fire tonechange events at the expected time');
-
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('abc', 100, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 170],
- ['C', '', 170],
- ['', '', 170]
- ], 'insertDTMF() with explicit duration and intertoneGap should fire tonechange events at the expected time');
-
- /*
- 7.2. insertDTMF
- 10. If toneBuffer is an empty string, abort these steps.
- */
- async_test(t => {
- createDtmfSender()
- .then(dtmfSender => {
- dtmfSender.addEventListener('tonechange',
- t.unreached_func('Expect no tonechange event to be fired'));
-
- dtmfSender.insertDTMF('', 100, 70);
-
- t.step_timeout(t.step_func_done(), 300);
- })
- .catch(t.step_func(err => {
- assert_unreached(`Unexpected promise rejection: ${err}`);
- }));
- }, `insertDTMF('') should not fire any tonechange event, including for '' tone`);
-
- /*
- 7.2. insertDTMF
- 8. If the value of the duration parameter is less than 40, set it to 40.
- If, on the other hand, the value is greater than 6000, set it to 6000.
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('ABC', 10, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 110],
- ['C', '', 110],
- ['', '', 110]
- ], 'insertDTMF() with duration less than 40 should be clamped to 40');
-
- /*
- 7.2. insertDTMF
- 9. If the value of the interToneGap parameter is less than 30, set it to 30.
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('ABC', 100, 10);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 130],
- ['C', '', 130],
- ['', '', 130]
- ],
- 'insertDTMF() with interToneGap less than 30 should be clamped to 30');
-
- /*
- [w3c/webrtc-pc#1373]
- This step is added to handle the "," character correctly. "," supposed to delay the next
- tonechange event by 2000ms.
-
- 7.2. insertDTMF
- 11.5. If tone is "," delay sending tones for 2000 ms on the associated RTP media
- stream, and queue a task to be executed in 2000 ms from now that runs the
- steps labelled Playout task.
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.insertDTMF('A,B', 100, 70);
-
- }, [
- ['A', ',B', 0],
- [',', 'B', 170],
- ['B', '', 2000],
- ['', '', 170]
- ], 'insertDTMF with comma should delay next tonechange event for a constant 2000ms');
-
- /*
- 7.2. insertDTMF
- 11.1. If transceiver.stopped is true, abort these steps.
- */
- test_tone_change_events((t, dtmfSender, pc) => {
- const transceiver = getTransceiver(pc);
- dtmfSender.addEventListener('tonechange', ev => {
- if(ev.tone === 'B') {
- transceiver.stop();
- }
- });
-
- dtmfSender.insertDTMF('ABC', 100, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 170]
- ], 'insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing');
-
- /*
- 7.2. insertDTMF
- 3. If a Playout task is scheduled to be run, abort these steps;
- otherwise queue a task that runs the following steps (Playout task):
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.addEventListener('tonechange', ev => {
- if(ev.tone === 'B') {
- dtmfSender.insertDTMF('12', 100, 70);
- }
- });
-
- dtmfSender.insertDTMF('ABC', 100, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 170],
- ['1', '2', 170],
- ['2', '', 170],
- ['', '', 170]
- ], 'Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones');
-
-
- /*
- 7.2. insertDTMF
- 3. If a Playout task is scheduled to be run, abort these steps;
- otherwise queue a task that runs the following steps (Playout task):
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.addEventListener('tonechange', ev => {
- if(ev.tone === 'B') {
- dtmfSender.insertDTMF('12', 100, 70);
- dtmfSender.insertDTMF('34', 100, 70);
- }
- });
-
- dtmfSender.insertDTMF('ABC', 100, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 170],
- ['3', '4', 170],
- ['4', '', 170],
- ['', '', 170]
- ], 'Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones');
-
- /*
- 7.2. insertDTMF
- 3. If a Playout task is scheduled to be run, abort these steps;
- otherwise queue a task that runs the following steps (Playout task):
- */
- test_tone_change_events((t, dtmfSender) => {
- dtmfSender.addEventListener('tonechange', ev => {
- if(ev.tone === 'B') {
- dtmfSender.insertDTMF('');
- }
- });
-
- dtmfSender.insertDTMF('ABC', 100, 70);
- }, [
- ['A', 'BC', 0],
- ['B', 'C', 170],
- ['', '', 170]
- ], `Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing`);
-
- /*
- 7.2. insertDTMF
- 11.2. If transceiver.currentDirection is recvonly or inactive, abort these steps.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const dtmfSender = await createDtmfSender(pc);
- const pc2 = pc.otherPc;
- assert_true(pc2 instanceof RTCPeerConnection,
- 'Expect pc2 to be a RTCPeerConnection');
- t.add_cleanup(() => pc2.close());
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.sender.dtmf, dtmfSender);
-
- // Since setRemoteDescription happens in parallel with tonechange event,
- // We use a flag and allow tonechange events to be fired as long as
- // the promise returned by setRemoteDescription is not yet resolved.
- let remoteDescriptionIsSet = false;
-
- // We only do basic tone verification and not check timing here
- let expectedTones = ['A', 'B', 'C', 'D', ''];
-
- const firstTone = new Promise(resolve => {
- const onToneChange = t.step_func(ev => {
- assert_false(remoteDescriptionIsSet,
- 'Expect no tonechange event to be fired after currentDirection is changed to recvonly');
-
- const { tone } = ev;
- const expectedTone = expectedTones.shift();
- assert_equals(tone, expectedTone,
- `Expect fired event.tone to be ${expectedTone}`);
-
- if(tone === 'A') {
- resolve();
- }
- });
- dtmfSender.addEventListener('tonechange', onToneChange);
- });
-
- dtmfSender.insertDTMF('ABCD', 100, 70);
- await firstTone;
-
- // Only change transceiver.direction after the first
- // tonechange event, to make sure that tonechange is triggered
- // then stopped
- transceiver.direction = 'recvonly';
- await exchangeOfferAnswer(pc, pc2);
- assert_equals(transceiver.currentDirection, 'inactive');
- remoteDescriptionIsSet = true;
-
- await new Promise(resolve => t.step_timeout(resolve, 300));
- }, `Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing`);
-
- /* Section 7.3 - Tone change event */
- test(t => {
- let ev = new RTCDTMFToneChangeEvent('tonechange', {'tone': '1'});
- assert_equals(ev.type, 'tonechange');
- assert_equals(ev.tone, '1');
- }, 'Tone change event constructor works');
-
- test(t => {
- let ev = new RTCDTMFToneChangeEvent('worngname', {});
- }, 'Tone change event with unexpected name should not crash');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCDataChannel.prototype.bufferedAmount</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// createDataChannelPair
-// awaitMessage
-
-/*
- 6.2. RTCDataChannel
- interface RTCDataChannel : EventTarget {
- ...
- readonly attribute unsigned long bufferedAmount;
- void send(USVString data);
- void send(Blob data);
- void send(ArrayBuffer data);
- void send(ArrayBufferView data);
- };
-
- bufferedAmount
- The bufferedAmount attribute must return the number of bytes of application
- data (UTF-8 text and binary data) that have been queued using send() but that,
- as of the last time the event loop started executing a task, had not yet been
- transmitted to the network. (This thus includes any text sent during the
- execution of the current task, regardless of whether the user agent is able
- to transmit text asynchronously with script execution.) This does not include
- framing overhead incurred by the protocol, or buffering done by the operating
- system or network hardware. The value of the [[BufferedAmount]] slot will only
- increase with each call to the send() method as long as the [[ReadyState]] slot
- is open; however, the slot does not reset to zero once the channel closes. When
- the underlying data transport sends data from its queue, the user agent MUST
- queue a task that reduces [[BufferedAmount]] with the number of bytes that was
- sent.
-
-
- [WebMessaging]
- interface MessageEvent : Event {
- readonly attribute any data;
- ...
- };
- */
-
-// Simple ASCII encoded string
-const helloString = 'hello';
-// ASCII encoded buffer representation of the string
-const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
-const helloBlob = new Blob([helloBuffer]);
-
-// Unicode string with multiple code units
-const unicodeString = 'äļįä― åĨ―';
-// UTF-8 encoded buffer representation of the string
-const unicodeBuffer = Uint8Array.of(
- 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c,
- 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd);
-
-for (const options of [{}, {negotiated: true, id: 0}]) {
- const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
-
- /*
- Ensure .bufferedAmount is 0 initially for both sides.
- */
- promise_test(async (t) => {
- const [dc1, dc2] = await createDataChannelPair(t, options);
-
- assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
- assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
- }, `${mode} bufferedAmount initial value should be 0 for both peers`);
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
-
- string object
- Let data be the object and increase the bufferedAmount attribute
- by the number of bytes needed to express data as UTF-8.
- */
- promise_test(async (t) => {
- const [dc1, dc2] = await createDataChannelPair(t, options);
-
- dc1.send(unicodeString);
- assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength,
- 'Expect bufferedAmount to be the byte length of the unicode string');
-
- await awaitMessage(dc2);
- assert_equals(dc1.bufferedAmount, 0,
- 'Expect sender bufferedAmount to be reduced after message is sent');
- }, `${mode} bufferedAmount should increase to byte length of encoded` +
- `unicode string sent`);
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
- ArrayBuffer object
- Let data be the data stored in the buffer described by the ArrayBuffer
- object and increase the bufferedAmount attribute by the length of the
- ArrayBuffer in bytes.
- */
- promise_test(async (t) => {
- const [dc1, dc2] = await createDataChannelPair(t, options);
-
- dc1.send(helloBuffer.buffer);
- assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
- 'Expect bufferedAmount to increase to byte length of sent buffer');
-
- await awaitMessage(dc2);
- assert_equals(dc1.bufferedAmount, 0,
- 'Expect sender bufferedAmount to be reduced after message is sent');
- }, `${mode} bufferedAmount should increase to byte length of buffer sent`);
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
- Blob object
- Let data be the raw data represented by the Blob object and increase
- the bufferedAmount attribute by the size of data, in bytes.
- */
-
- promise_test(async (t) => {
- const [dc1] = await createDataChannelPair(t, options);
-
- dc1.send(helloBuffer.buffer);
- assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
- 'Expect bufferedAmount to increase to byte length of sent buffer');
-
- dc1.close();
- assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
- 'Expect bufferedAmount to not decrease immediately after closing the channel');
- }, `${mode} bufferedAmount should not decrease immediately after initiating closure`);
-
- promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const [dc1] = await createDataChannelPair(t, options, pc1);
-
- dc1.send(helloBuffer.buffer);
- assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
- 'Expect bufferedAmount to increase to byte length of sent buffer');
-
- pc1.close();
- assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
- 'Expect bufferedAmount to not decrease after closing the peer connection');
- }, `${mode} bufferedAmount should not decrease after closing the peer connection`);
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- channel1.addEventListener('bufferedamountlow', t.step_func_done(() => {
- assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
- }));
- const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
- channel1.send(helloString);
- await eventWatcher.wait_for(['bufferedamountlow']);
- }, `${mode} bufferedamountlow event fires after send() is complete`);
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, helloString.length);
- await awaitMessage(channel2);
- assert_equals(channel1.bufferedAmount, 0);
- }, `${mode} bufferedamount is data.length on send(data)`);
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, helloString.length);
- assert_equals(channel1.bufferedAmount, helloString.length);
- }, `${mode} bufferedamount returns the same amount if no more data is`);
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- let eventFireCount = 0;
- channel1.addEventListener('bufferedamountlow', t.step_func(() => {
- assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
- assert_equals(++eventFireCount, 1);
- }));
- const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, helloString.length);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, 2 * helloString.length);
- await eventWatcher.wait_for(['bufferedamountlow']);
- }, `${mode} bufferedamountlow event fires only once after multiple` +
- ` consecutive send() calls`);
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, helloString.length);
- await eventWatcher.wait_for(['bufferedamountlow']);
- assert_equals(await awaitMessage(channel2), helloString);
- channel1.send(helloString);
- assert_equals(channel1.bufferedAmount, helloString.length);
- await eventWatcher.wait_for(['bufferedamountlow']);
- assert_equals(await awaitMessage(channel2), helloString);
- }, `${mode} bufferedamountlow event fires after each sent message`);
-}
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCDataChannel.prototype.close</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-for (const options of [{}, {negotiated: true, id: 0}]) {
- const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
-
- promise_test(async t => {
- const [channel1, channel2] = await createDataChannelPair(t, options);
- const haveClosed = new Promise(r => channel2.onclose = r);
- let closingSeen = false;
- channel1.onclosing = t.unreached_func();
- channel2.onclosing = () => {
- assert_equals(channel2.readyState, 'closing');
- closingSeen = true;
- };
- channel2.addEventListener('error', t.unreached_func());
- channel1.close();
- await haveClosed;
- assert_equals(channel2.readyState, 'closed');
- assert_true(closingSeen, 'Closing event was seen');
- }, `Close ${mode} causes onclosing and onclose to be called`);
-
- promise_test(async t => {
- // This is the same test as above, but using addEventListener
- // rather than the "onclose" attribute.
- const [channel1, channel2] = await createDataChannelPair(t, options);
- const haveClosed = new Promise(r => channel2.addEventListener('close', r));
- let closingSeen = false;
- channel1.addEventListener('closing', t.unreached_func());
- channel2.addEventListener('closing', () => {
- assert_equals(channel2.readyState, 'closing');
- closingSeen = true;
- });
- channel2.addEventListener('error', t.unreached_func());
- channel1.close();
- await haveClosed;
- assert_equals(channel2.readyState, 'closed');
- assert_true(closingSeen, 'Closing event was seen');
- }, `Close ${mode} causes closing and close event to be called`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const [channel1, channel2] = await createDataChannelPair(t, options, pc1);
- const events = [];
- let error = null;
- channel2.addEventListener('error', t.step_func(event => {
- events.push('error');
- assert_true(event instanceof RTCErrorEvent);
- error = event.error;
- }));
- const haveClosed = new Promise(r => channel2.addEventListener('close', () => {
- events.push('close');
- r();
- }));
- pc1.close();
- await haveClosed;
- // Error should fire before close.
- assert_array_equals(events, ['error', 'close']);
- assert_true(error instanceof RTCError);
- assert_equals(error.name, 'OperationError');
- assert_equals(error.errorDetail, 'sctp-failure');
- // Expects the sctpErrorCode is either null or 12 (User-Initiated Abort) as it is
- // optional in the SCTP specification.
- assert_in_array(error.sctpCauseCode, [null, 12]);
- }, `Close peerconnection causes close event and error to be called on ${mode}`);
-
- promise_test(async t => {
- let pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- let [channel1, channel2] = await createDataChannelPair(t, options, pc1);
- // The expected sequence of events when closing a DC is that
- // channel1 goes to closing, channel2 fires onclose, and when
- // the close is confirmed, channel1 fires onclose.
- // After that, no more events should fire.
- channel1.onerror = t.unreached_func();
- let close2Handler = new Promise(resolve => {
- channel2.onclose = event => {
- resolve();
- };
- });
- let close1Handler = new Promise(resolve => {
- channel1.onclose = event => {
- resolve();
- };
- });
- channel1.close();
- await close2Handler;
- await close1Handler;
- channel1.onclose = t.unreached_func();
- channel2.onclose = t.unreached_func();
- channel2.onerror = t.unreached_func();
- pc1.close();
- await new Promise(resolve => t.step_timeout(resolve, 10));
- }, `Close peerconnection after ${mode} close causes no events`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('not-counted', options);
- const tokenDataChannel = new Promise(resolve => {
- pc2.ondatachannel = resolve;
- });
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- if (!options.negotiated) {
- await tokenDataChannel;
- }
- let closeExpectedCount = 0;
- let errorExpectedCount = 0;
- let resolveCountIsZero;
- let waitForCountIsZero = new Promise(resolve => {
- resolveCountIsZero = resolve;
- });
- for (let i = 1; i <= 10; i++) {
- if ('id' in options) {
- options.id = i;
- }
- pc1.createDataChannel('', options);
- if (options.negotiated) {
- const channel = pc2.createDataChannel('', options);
- channel.addEventListener('error', t.step_func(event => {
- assert_true(event instanceof RTCErrorEvent, 'error event ' + event);
- errorExpectedCount -= 1;
- }));
- channel.addEventListener('close', t.step_func(event => {
- closeExpectedCount -= 1;
- if (closeExpectedCount == 0) {
- resolveCountIsZero();
- }
- }));
- } else {
- await new Promise(resolve => {
- pc2.ondatachannel = ({channel}) => {
- channel.addEventListener('error', t.step_func(event => {
- assert_true(event instanceof RTCErrorEvent);
- errorExpectedCount -= 1;
- }));
- channel.addEventListener('close', t.step_func(event => {
- closeExpectedCount -= 1;
- if (closeExpectedCount == 0) {
- resolveCountIsZero();
- }
- }));
- resolve();
- }
- });
- }
- ++closeExpectedCount;
- ++errorExpectedCount;
- }
- assert_equals(closeExpectedCount, 10);
- // We have to wait until SCTP is connected before we close, otherwise
- // there will be no signal.
- // The state is not available under Plan B, and unreliable on negotiated
- // channels.
- // TODO(bugs.webrtc.org/12259): Remove dependency on "negotiated"
- if (pc1.sctp && !options.negotiated) {
- waitForState(pc1.sctp, 'connected');
- } else {
- // Under plan B, we don't have a dtls transport to wait on, so just
- // wait a bit.
- await new Promise(resolve => t.step_timeout(resolve, 100));
- }
- pc1.close();
- await waitForCountIsZero;
- assert_equals(closeExpectedCount, 0);
- assert_equals(errorExpectedCount, 0);
- }, `Close peerconnection causes close event and error on many channels, ${mode}`);
-}
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCDataChannel interactions with ICE restart</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-async function checkCanPassData(channel1, channel2) {
- channel1.send('hello');
- const message = await awaitMessage(channel2);
- assert_equals(message, 'hello');
-}
-
-async function pingPongData(channel1, channel2, size=1) {
- channel1.send('hello');
- const request = await awaitMessage(channel2);
- assert_equals(request, 'hello');
- const response = 'x'.repeat(size);
- channel2.send(response);
- const responseReceived = await awaitMessage(channel1);
- assert_equals(response, responseReceived);
-}
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const [channel1, channel2] = await createDataChannelPair(t, {}, pc1, pc2);
- channel2.addEventListener('error', t.unreached_func());
- channel2.addEventListener('error', t.unreached_func());
-
- await checkCanPassData(channel1, channel2);
- await checkCanPassData(channel2, channel1);
-
- pc1.restartIce();
- await exchangeOfferAnswer(pc1, pc2);
-
- await checkCanPassData(channel1, channel2);
- await checkCanPassData(channel2, channel1);
- channel1.close();
- channel2.close();
-}, `Data channel remains usable after ICE restart`);
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const [channel1, channel2] = await createDataChannelPair(t, {}, pc1, pc2);
- channel2.addEventListener('error', t.unreached_func());
- channel2.addEventListener('error', t.unreached_func());
-
- await pingPongData(channel1, channel2);
- pc1.restartIce();
-
- await pc1.setLocalDescription();
- await pingPongData(channel1, channel2);
- await pc2.setRemoteDescription(pc1.localDescription);
- await pingPongData(channel1, channel2);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pingPongData(channel1, channel2);
- await pc1.setRemoteDescription(pc2.localDescription);
- await pingPongData(channel1, channel2);
- channel1.close();
- channel2.close();
-}, `Data channel remains usable at each step of an ICE restart`);
-
-
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCDataChannel id attribute</title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-// This is the maximum number of streams, NOT the maximum stream ID (which is 65534)
-// See: https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2
-const nStreams = 65535;
-
-/*
- 6.1.
- 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
- createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
- transport has already been negotiated, then initialize [[DataChannelId]] to a value
- generated by the user agent, according to [RTCWEB-DATA-PROTOCOL] [...]
- */
-promise_test(async (t) => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc1 = pc.createDataChannel('');
- const ids = new UniqueSet();
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- // Turn our own offer SDP into valid answer SDP by setting the DTLS role to
- // "active".
- const answer = {
- type: 'answer',
- sdp: pc.localDescription.sdp.replace('actpass', 'active')
- };
- await pc.setRemoteDescription(answer);
-
- // Since the remote description had an 'active' DTLS role, we're the server
- // and should use odd data channel IDs, according to rtcweb-data-channel.
- assert_equals(dc1.id % 2, 1,
- `Channel created by the DTLS server role must be odd (was ${dc1.id})`);
- const dc2 = pc.createDataChannel('another');
- assert_equals(dc2.id % 2, 1,
- `Channel created by the DTLS server role must be odd (was ${dc2.id})`);
-
- // Ensure IDs are unique
- ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
- ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
-}, 'DTLS client uses odd data channel IDs');
-
-promise_test(async (t) => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc1 = pc.createDataChannel('');
- const ids = new UniqueSet();
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- // Turn our own offer SDP into valid answer SDP by setting the DTLS role to
- // 'passive'.
- const answer = {
- type: 'answer',
- sdp: pc.localDescription.sdp.replace('actpass', 'passive')
- };
- await pc.setRemoteDescription(answer);
-
- // Since the remote description had a 'passive' DTLS role, we're the client
- // and should use even data channel IDs, according to rtcweb-data-channel.
- assert_equals(dc1.id % 2, 0,
- `Channel created by the DTLS client role must be even (was ${dc1.id})`);
- const dc2 = pc.createDataChannel('another');
- assert_equals(dc2.id % 2, 0,
- `Channel created by the DTLS client role must be even (was ${dc1.id})`);
-
- // Ensure IDs are unique
- ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
- ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
-}, 'DTLS server uses even data channel IDs');
-
-/*
- Checks that the id is ignored if "negotiated" is false.
- See section 6.1, createDataChannel step 13.
- */
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel('', {
- negotiated: false,
- id: 42
- });
- dc1.onopen = t.step_func(() => {
- dc1.send(':(');
- });
-
- const dc2 = pc2.createDataChannel('', {
- negotiated: false,
- id: 42
- });
- // ID should be null prior to negotiation.
- assert_equals(dc1.id, null);
- assert_equals(dc2.id, null);
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- // We should now have 2 datachannels with different IDs.
- // At least one of the datachannels should not be 42.
- // If one has the value 42, it's an accident; if both have,
- // they are the same datachannel, and it's a bug.
- assert_false(dc1.id == 42 && dc2.id == 42);
-}, 'In-band negotiation with a specific ID should not work');
-
-/*
- Check if the implementation still follows the odd/even role correctly if we annoy it with
- negotiated channels not following that rule.
-
- Note: This test assumes that the implementation can handle a minimum of 40 data channels.
- */
-promise_test(async (t) => {
- // Takes the DTLS server role
- const pc1 = new RTCPeerConnection();
- // Takes the DTLS client role
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- exchangeIceCandidates(pc1, pc2);
- const dcs = [];
- const negotiatedDcs = [];
- const ids = new UniqueSet();
-
- // Create 10 DCEP-negotiated channels with pc1
- // Note: These should not have any associated valid ID at this point
- for (let i = 0; i < 10; ++i) {
- const dc = pc1.createDataChannel('before-connection');
- assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
- dcs.push(dc);
- }
-
- // Create 10 negotiated channels with pc1 violating the odd/even rule
- for (let id = 0; id < 20; id += 2) {
- const dc = pc1.createDataChannel(`negotiated-not-odd-${id}-before-connection`, {
- negotiated: true,
- id: id,
- });
- assert_equals(dc.id, id, 'Channel id must be set before DTLS role has been determined when negotiated is true');
- negotiatedDcs.push([dc, id]);
- ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
- }
-
- await exchangeOfferAnswer(pc1, pc2, {
- offer: (offer) => {
- // Ensure pc1 takes the server role
- assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
- 'pc1 must take the DTLS server role');
- return offer;
- },
- answer: (answer) => {
- // Ensure pc2 takes the client role
- // Note: It very likely will choose 'active' itself
- answer.sdp = answer.sdp.replace('actpass', 'active');
- assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
- return answer;
- },
- });
-
- for (const dc of dcs) {
- assert_equals(dc.id % 2, 1,
- `Channel created by the DTLS server role must be odd (was ${dc.id})`);
- ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
- }
-
- // Create 10 channels with pc1
- for (let i = 0; i < 10; ++i) {
- const dc = pc1.createDataChannel('after-connection');
- assert_equals(dc.id % 2, 1,
- `Channel created by the DTLS server role must be odd (was ${dc.id})`);
- dcs.push(dc);
- ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
- }
-
- // Create 10 negotiated channels with pc1 violating the odd/even rule
- for (let i = 0; i < 10; ++i) {
- // Generate a valid even ID that has not been taken, yet.
- let id = 20;
- while (ids.has(id)) {
- id += 2;
- }
- const dc = pc1.createDataChannel(`negotiated-not-odd-${i}-after-connection`, {
- negotiated: true,
- id: id,
- });
- negotiatedDcs.push([dc, id]);
- ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
- }
-
- // Since we've added new channels, let's check again that the odd/even role is not violated
- for (const dc of dcs) {
- assert_equals(dc.id % 2, 1,
- `Channel created by the DTLS server role must be odd (was ${dc.id})`);
- }
-
- // Let's also make sure the negotiated channels have kept their ID
- for (const [dc, id] of negotiatedDcs) {
- assert_equals(dc.id, id, 'Negotiated channels should keep their assigned ID');
- }
-}, 'Odd/even role should not be violated when mixing with negotiated channels');
-
-/*
- Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted AFTER
- establishing a peer connection.
-
- 6.1. createDataChannel
- 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
- createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
- transport has already been negotiated, then initialize [[DataChannelId]] to a value
- generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
- to the next step. If no available ID could be generated, or if the value of the
- [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
- OperationError exception.
- */
-/*
- TODO: Improve test coverage for RTCSctpTransport.maxChannels.
- TODO: Improve test coverage for exhausting channel cases.
- */
-
-/*
- Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted BEFORE
- establishing a peer connection.
-
- Be aware that late channel id assignment can currently fail in many places not covered by the
- spec, see: https://github.com/w3c/webrtc-pc/issues/1818
-
- 4.4.1.6.
- 2.2.6. If description negotiates the DTLS role of the SCTP transport, and there is an
- RTCDataChannel with a null id, then generate an ID according to [RTCWEB-DATA-PROTOCOL].
- If no available ID could be generated, then run the following steps:
- 1. Let channel be the RTCDataChannel object for which an ID could not be generated.
- 2. Set channel's [[ReadyState]] slot to "closed".
- 3. Fire an event named error with an OperationError exception at channel.
- 4. Fire a simple event named close at channel.
- */
-/* TEST DISABLED - it takes so long, it times out.
-promise_test(async (t) => {
- const resolver = new Resolver();
- // Takes the DTLS server role
- const pc1 = new RTCPeerConnection();
- // Takes the DTLS client role
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- exchangeIceCandidates(pc1, pc2);
- const dcs = [];
- const ids = new UniqueSet();
- let nExpected = 0;
- let nActualCloses = 0;
- let nActualErrors = 0;
-
- const maybeDone = t.step_func(() => {
- if (nExpected === nActualCloses && nExpected === nActualErrors) {
- resolver.resolve();
- }
- });
-
- // Create 65535+2 channels (since 65535 streams is a SHOULD, we may have less than that.)
- // Create two extra channels to possibly trigger the steps in the description.
- //
- // Note: Following the spec strictly would assume that this cannot fail. But in reality it will
- // fail because the implementation knows how many streams it supports. What it doesn't
- // know is how many streams the other peer supports (e.g. what will be negotiated).
- for (let i = 0; i < (nStreams + 2); ++i) {
- let dc;
- try {
- const pc = i % 2 === 1 ? pc1 : pc2;
- dc = pc.createDataChannel('this is going to be fun');
- dc.onclose = t.step_func(() => {
- ++nActualCloses;
- maybeDone();
- });
- dc.onerror = t.step_func((e) => {
- assert_true(e instanceof RTCError, 'Expect error object to be instance of RTCError');
- assert_equals(e.error, 'sctp-failure', "Expect error to be of type 'sctp-failure'");
- ++nActualErrors;
- maybeDone();
- });
- } catch (e) {
- assert_equals(e.name, 'OperationError', 'Fail on creation should throw OperationError');
- break;
- }
- assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
- assert_not_equals(dc.readyState, 'closed',
- 'Channel may not be closed before connection establishment');
- dcs.push([dc, i % 2 === 1]);
- }
-
- await exchangeOfferAnswer(pc1, pc2, {
- offer: (offer) => {
- // Ensure pc1 takes the server role
- assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
- 'pc1 must take the DTLS server role');
- return offer;
- },
- answer: (answer) => {
- // Ensure pc2 takes the client role
- // Note: It very likely will choose 'active' itself
- answer.sdp = answer.sdp.replace('actpass', 'active');
- assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
- return answer;
- },
- });
-
- // Since the spec does not define a specific order to which channels may fail if an ID could
- // not be generated, any of the channels may be affected by the steps of the description.
- for (const [dc, odd] of dcs) {
- if (dc.readyState !== 'closed') {
- assert_equals(dc.id % 2, odd ? 1 : 0,
- `Channels created by the DTLS ${odd ? 'server' : 'client'} role must be
- ${odd ? 'odd' : 'even'} (was ${dc.id})`);
- ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
- } else {
- ++nExpected;
- }
- }
-
- // Try creating one further channel on both sides. The attempt should fail since all IDs are
- // taken. If one ID is available, the implementation probably miscounts (or I did in the test).
- assert_throws_dom('OperationError', () =>
- pc1.createDataChannel('this is too exhausting!'));
- assert_throws_dom('OperationError', () =>
- pc2.createDataChannel('this is too exhausting!'));
-
- maybeDone();
- await resolver;
-}, 'Channel ID exhaustion handling (before and after connection establishment)');
-
-END DISABLED TEST */
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCDataChannel.prototype.send</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
-// createDataChannelPair
-// awaitMessage
-// blobToArrayBuffer
-// assert_equals_typed_array
-
-/*
- 6.2. RTCDataChannel
- interface RTCDataChannel : EventTarget {
- ...
- readonly attribute RTCDataChannelState readyState;
- readonly attribute unsigned long bufferedAmount;
- attribute EventHandler onmessage;
- attribute DOMString binaryType;
-
- void send(USVString data);
- void send(Blob data);
- void send(ArrayBuffer data);
- void send(ArrayBufferView data);
- };
- */
-
-// Simple ASCII encoded string
-const helloString = 'hello';
-const emptyString = '';
-// ASCII encoded buffer representation of the string
-const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
-const emptyBuffer = new Uint8Array();
-const helloBlob = new Blob([helloBuffer]);
-
-// Unicode string with multiple code units
-const unicodeString = 'äļįä― åĨ―';
-// UTF-8 encoded buffer representation of the string
-const unicodeBuffer = Uint8Array.of(
- 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c,
- 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd);
-
-/*
- 6.2. send()
- 2. If channel's readyState attribute is connecting, throw an InvalidStateError.
- */
-test(t => {
- const pc = new RTCPeerConnection();
- const channel = pc.createDataChannel('test');
- assert_equals(channel.readyState, 'connecting');
- assert_throws_dom('InvalidStateError', () => channel.send(helloString));
-}, 'Calling send() when data channel is in connecting state should throw InvalidStateError');
-
-for (const options of [{}, {negotiated: true, id: 0}]) {
- const mode = `${options.negotiated? "Negotiated d" : "D"}atachannel`;
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
-
- string object
- Let data be the object and increase the bufferedAmount attribute
- by the number of bytes needed to express data as UTF-8.
-
- [WebSocket]
- 5. Feedback from the protocol
- When a WebSocket message has been received
- 4. If type indicates that the data is Text, then initialize event's data
- attribute to data.
- */
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel1.send(helloString);
- return awaitMessage(channel2)
- }).then(message => {
- assert_equals(typeof message, 'string',
- 'Expect message to be a string');
-
- assert_equals(message, helloString);
- });
- }, `${mode} should be able to send simple string and receive as string`);
-
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel1.send(unicodeString);
- return awaitMessage(channel2)
- }).then(message => {
- assert_equals(typeof message, 'string',
- 'Expect message to be a string');
-
- assert_equals(message, unicodeString);
- });
- }, `${mode} should be able to send unicode string and receive as unicode string`);
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel2.binaryType = 'arraybuffer';
- channel1.send(helloString);
- return awaitMessage(channel2);
- }).then(message => {
- assert_equals(typeof message, 'string',
- 'Expect message to be a string');
-
- assert_equals(message, helloString);
- });
- }, `${mode} should ignore binaryType and always receive string message as string`);
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel1.send(emptyString);
- // Send a non-empty string in case the implementation ignores empty messages
- channel1.send(helloString);
- return awaitMessage(channel2)
- }).then(message => {
- assert_equals(typeof message, 'string',
- 'Expect message to be a string');
-
- assert_equals(message, emptyString);
- });
- }, `${mode} should be able to send an empty string and receive an empty string`);
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
- ArrayBufferView object
- Let data be the data stored in the section of the buffer described
- by the ArrayBuffer object that the ArrayBufferView object references
- and increase the bufferedAmount attribute by the length of the
- ArrayBufferView in bytes.
-
- [WebSocket]
- 5. Feedback from the protocol
- When a WebSocket message has been received
- 4. If binaryType is set to "arraybuffer", then initialize event's data
- attribute to a new read-only ArrayBuffer object whose contents are data.
-
- [WebIDL]
- 4.1. ArrayBufferView
- typedef (Int8Array or Int16Array or Int32Array or
- Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
- Float32Array or Float64Array or DataView) ArrayBufferView;
- */
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel2.binaryType = 'arraybuffer';
- channel1.send(helloBuffer);
- return awaitMessage(channel2)
- }).then(messageBuffer => {
- assert_true(messageBuffer instanceof ArrayBuffer,
- 'Expect messageBuffer to be an ArrayBuffer');
-
- assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
- });
- }, `${mode} should be able to send Uint8Array message and receive as ArrayBuffer`);
-
- /*
- 6.2. send()
- 3. Execute the sub step that corresponds to the type of the methods argument:
- ArrayBuffer object
- Let data be the data stored in the buffer described by the ArrayBuffer
- object and increase the bufferedAmount attribute by the length of the
- ArrayBuffer in bytes.
- */
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel2.binaryType = 'arraybuffer';
- channel1.send(helloBuffer.buffer);
- return awaitMessage(channel2)
- }).then(messageBuffer => {
- assert_true(messageBuffer instanceof ArrayBuffer,
- 'Expect messageBuffer to be an ArrayBuffer');
-
- assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
- });
- }, `${mode} should be able to send ArrayBuffer message and receive as ArrayBuffer`);
-
- promise_test(t => {
- return createDataChannelPair(t, options)
- .then(([channel1, channel2]) => {
- channel2.binaryType = 'arraybuffer';
- channel1.send(emptyBuffer.buffer);
- // Send a non-empty buffer in case the implementation ignores empty messages
- channel1.send(helloBuffer.buffer);
- return awaitMessage(channel2)
- }).then(messageBuffer => {
- assert_true(messageBuffer instanceof ArrayBuffer,
- 'Expect messageBuffer to be an ArrayBuffer');
-
- assert_equals_typed_array(messageBuffer, emptyBuffer.buffer);
- });
- }, `${mode} should be able to send an empty ArrayBuffer message and receive as ArrayBuffer`);
-
-}
-</script>
+++ /dev/null
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>RTCDataChannelEvent constructor</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-test(function() {
- assert_equals(RTCDataChannelEvent.length, 2);
- assert_throws_js(
- TypeError,
- function() { new RTCDataChannelEvent('type'); }
- );
-}, 'RTCDataChannelEvent constructor without a required argument.');
-
-test(function() {
- assert_throws_js(
- TypeError,
- function() { new RTCDataChannelEvent('type', { channel: null }); }
- );
-}, 'RTCDataChannelEvent constructor with channel passed as null.');
-
-test(function() {
- assert_throws_js(
- TypeError,
- function() { new RTCDataChannelEvent('type', { channel: undefined }); }
- );
-}, 'RTCDataChannelEvent constructor with a channel passed as undefined.');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('');
- const event = new RTCDataChannelEvent('type', { channel: dc });
- assert_true(event instanceof RTCDataChannelEvent);
- assert_equals(event.channel, dc);
-}, 'RTCDataChannelEvent constructor with full arguments.');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>RTCDtlsTransport.prototype.getRemoteCertificates</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // exchangeIceCandidates
- // exchangeOfferAnswer
-
- /*
- 5.5. RTCDtlsTransport Interface
- interface RTCDtlsTransport : EventTarget {
- readonly attribute RTCDtlsTransportState state;
- sequence<ArrayBuffer> getRemoteCertificates();
- attribute EventHandler onstatechange;
- attribute EventHandler onerror;
- ...
- };
-
- enum RTCDtlsTransportState {
- "new",
- "connecting",
- "connected",
- "closed",
- "failed"
- };
-
- getRemoteCertificates
- Returns the certificate chain in use by the remote side, with each certificate
- encoded in binary Distinguished Encoding Rules (DER) [X690].
- getRemoteCertificates() will return an empty list prior to selection of the
- remote certificate, which will be completed by the time RTCDtlsTransportState
- transitions to "connected".
- */
- async_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(trackFactories.audio());
- exchangeIceCandidates(pc1, pc2);
-
- exchangeOfferAnswer(pc1, pc2)
- .then(t.step_func(() => {
- const dtlsTransport1 = pc1.getSenders()[0].transport;
- const dtlsTransport2 = pc2.getReceivers()[0].transport;
-
- const testedTransports = new Set();
-
- // Callback function that test the respective DTLS transports
- // when they become connected.
- const onConnected = t.step_func(dtlsTransport => {
- const certs = dtlsTransport.getRemoteCertificates();
-
- assert_greater_than(certs.length, 0,
- 'Expect DTLS transport to have at least one remote certificate when connected');
-
- for(const cert of certs) {
- assert_true(cert instanceof ArrayBuffer,
- 'Expect certificate elements be instance of ArrayBuffer');
- }
-
- testedTransports.add(dtlsTransport);
-
- // End the test if both dtlsTransports are tested.
- if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtlsTransport2)) {
- t.done();
- }
- })
-
- for(const dtlsTransport of [dtlsTransport1, dtlsTransport2]) {
- if(dtlsTransport.state === 'connected') {
- onConnected(dtlsTransport);
- } else {
- assert_array_equals(dtlsTransport.getRemoteCertificates(), [],
- 'Expect DTLS certificates be initially empty until become connected');
-
- dtlsTransport.addEventListener('statechange', t.step_func(() => {
- if(dtlsTransport.state === 'connected') {
- onConnected(dtlsTransport);
- }
- }));
-
- dtlsTransport.addEventListener('error', t.step_func(err => {
- assert_unreached(`Unexpected error during DTLS handshake: ${err}`);
- }));
- }
- }
- }));
- });
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>RTCDtlsTransport</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// exchangeIceCandidates
-// exchangeOfferAnswer
-// trackFactories.audio()
-
-/*
- 5.5. RTCDtlsTransport Interface
- interface RTCDtlsTransport : EventTarget {
- readonly attribute RTCDtlsTransportState state;
- sequence<ArrayBuffer> getRemoteCertificates();
- attribute EventHandler onstatechange;
- attribute EventHandler onerror;
- ...
- };
-
- enum RTCDtlsTransportState {
- "new",
- "connecting",
- "connected",
- "closed",
- "failed"
- };
-
-*/
-function resolveWhen(t, dtlstransport, state) {
- return new Promise((resolve, reject) => {
- if (dtlstransport.state == state) { resolve(); }
- dtlstransport.addEventListener('statechange', t.step_func(e => {
- if (dtlstransport.state == state) {
- resolve();
- }
- }));
- });
-}
-
-
-async function setupConnections(t) {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(trackFactories.audio());
- const channels = exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- return [pc1, pc2];
-}
-
-promise_test(async t => {
- const [pc1, pc2] = await setupConnections(t);
- const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
- const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
- assert_true(dtlsTransport1 instanceof RTCDtlsTransport);
- assert_true(dtlsTransport2 instanceof RTCDtlsTransport);
- await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
- resolveWhen(t, dtlsTransport2, 'connected')]);
-}, 'DTLS transport goes to connected state');
-
-promise_test(async t => {
- const [pc1, pc2] = await setupConnections(t);
-
- const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
- const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
- await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
- resolveWhen(t, dtlsTransport2, 'connected')]);
- pc1.close();
- assert_equals(dtlsTransport1.state, 'closed');
-}, 'close() causes the local transport to close immediately');
-
-promise_test(async t => {
- const [pc1, pc2] = await setupConnections(t);
- const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
- const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
- await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
- resolveWhen(t, dtlsTransport2, 'connected')]);
- pc1.close();
- await resolveWhen(t, dtlsTransport2, 'closed');
-}, 'close() causes the other end\'s DTLS transport to close');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCError and RTCErrorInit</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_equals(error.message, 'message');
- assert_equals(error.errorDetail, 'data-channel-failure');
-}, 'RTCError constructor with errorDetail and message');
-
-test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'});
- assert_equals(error.message, '');
-}, 'RTCError constructor\'s message argument is optional');
-
-test(() => {
- assert_throws_js(TypeError, () => {
- new RTCError();
- });
- assert_throws_js(TypeError, () => {
- new RTCError({}); // {errorDetail} is missing.
- });
-}, 'RTCError constructor throws TypeError if arguments are missing');
-
-test(() => {
- assert_throws_js(TypeError, () => {
- new RTCError({errorDetail:'invalid-error-detail'}, 'message');
- });
-}, 'RTCError constructor throws TypeError if the errorDetail is invalid');
-
-test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_equals(error.name, 'OperationError');
-}, 'RTCError.name is \'OperationError\'');
-
-test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_equals(error.code, 0);
-}, 'RTCError.code is 0');
-
-test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_throws_js(TypeError, () => {
- error.errorDetail = 'dtls-failure';
- });
-}, 'RTCError.errorDetail is readonly.');
-
-test(() => {
- // Infers what are valid RTCErrorInit objects by passing them to the RTCError
- // constructor.
- assert_throws_js(TypeError, () => {
- new RTCError({}, 'message');
- });
- new RTCError({errorDetail:'data-channel-failure'}, 'message');
-}, 'RTCErrorInit.errorDetail is the only required attribute');
-
-// All of these are number types (long or unsigned long).
-const nullableAttributes = ['sdpLineNumber',
- 'httpRequestStatusCode',
- 'sctpCauseCode',
- 'receivedAlert',
- 'sentAlert'];
-
-nullableAttributes.forEach(attribute => {
- test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_equals(error[attribute], null);
- }, 'RTCError.' + attribute + ' is null by default');
-
- test(() => {
- const error = new RTCError(
- {errorDetail:'data-channel-failure', [attribute]: 0}, 'message');
- assert_equals(error[attribute], 0);
- }, 'RTCError.' + attribute + ' is settable by constructor');
-
- test(() => {
- const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
- assert_throws_js(TypeError, () => {
- error[attribute] = 42;
- });
- }, 'RTCError.' + attribute + ' is readonly');
-});
-
-</script>
+++ /dev/null
-<!doctype html>
-<title>RTCIceCandidate constructor</title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script>
- 'use strict';
-
- const candidateString = 'candidate:1905690388 1 udp 2113937151 192.168.0.1 58041 typ host generation 0 ufrag thC8 network-cost 50';
- const candidateString2 = 'candidate:435653019 2 tcp 1845501695 192.168.0.196 4444 typ srflx raddr www.example.com rport 22222 tcptype active';
- const arbitraryString = '<arbitrary string[0] content>;';
-
- test(t => {
- // The argument for RTCIceCandidateInit is optional (w3c/webrtc-pc #1153 #1166),
- // but the constructor throws because both sdpMid and sdpMLineIndex are null by default.
- // Note that current browsers pass this test but may throw TypeError for
- // different reason, i.e. they don't accept empty argument.
- // Further tests below are used to differentiate the errors.
- assert_throws_js(TypeError, () => new RTCIceCandidate());
- }, 'new RTCIceCandidate()');
-
- test(t => {
- // All fields in RTCIceCandidateInit are optional,
- // but the constructor throws because both sdpMid and sdpMLineIndex are null by default.
- // Note that current browsers pass this test but may throw TypeError for
- // different reason, i.e. they don't allow undefined candidate string.
- // Further tests below are used to differentiate the errors.
- assert_throws_js(TypeError, () => new RTCIceCandidate({}));
- }, 'new RTCIceCandidate({})');
-
- test(t => {
- // Checks that manually filling the default values for RTCIceCandidateInit
- // still throws because both sdpMid and sdpMLineIndex are null
- assert_throws_js(TypeError,
- () => new RTCIceCandidate({
- candidate: '',
- sdpMid: null,
- sdpMLineIndex: null,
- usernameFragment: undefined
- }));
- }, 'new RTCIceCandidate({ ... }) with manually filled default values');
-
- test(t => {
- // Checks that explicitly setting both sdpMid and sdpMLineIndex null should throw
- assert_throws_js(TypeError,
- () => new RTCIceCandidate({
- sdpMid: null,
- sdpMLineIndex: null
- }));
- }, 'new RTCIceCandidate({ sdpMid: null, sdpMLineIndex: null })');
-
- test(t => {
- // Throws because both sdpMid and sdpMLineIndex are null by default
- assert_throws_js(TypeError,
- () => new RTCIceCandidate({
- candidate: ''
- }));
- }, `new RTCIceCandidate({ candidate: '' })`);
-
- test(t => {
- // Throws because the candidate field is not nullable
- assert_throws_js(TypeError,
- () => new RTCIceCandidate({
- candidate: null
- }));
- }, `new RTCIceCandidate({ candidate: null })`);
-
- test(t => {
- // Throws because both sdpMid and sdpMLineIndex are null by default
- assert_throws_js(TypeError,
- () => new RTCIceCandidate({
- candidate: candidateString
- }));
- }, 'new RTCIceCandidate({ ... }) with valid candidate string only');
-
- test(t => {
- const candidate = new RTCIceCandidate({ sdpMid: 'audio' });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, `new RTCIceCandidate({ sdpMid: 'audio' })`);
-
- test(t => {
- const candidate = new RTCIceCandidate({ sdpMLineIndex: 0 });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, null, 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, 'new RTCIceCandidate({ sdpMLineIndex: 0 })');
-
- test(t => {
- const candidate = new RTCIceCandidate({
- sdpMid: 'audio',
- sdpMLineIndex: 0
- });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, `new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })`);
-
- test(t => {
- const candidate = new RTCIceCandidate({
- candidate: '',
- sdpMid: 'audio'
- });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, `new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }`);
-
- test(t => {
- const candidate = new RTCIceCandidate({
- candidate: '',
- sdpMLineIndex: 0
- });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, null, 'sdpMid', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, `new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }`);
-
- test(t => {
- const candidate = new RTCIceCandidate({
- candidate: candidateString,
- sdpMid: 'audio'
- });
-
- assert_equals(candidate.candidate, candidateString, 'candidate');
- assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, 'new RTCIceCandidate({ ... }) with valid candidate string and sdpMid');
-
- test(t =>{
- // candidate string is not validated in RTCIceCandidate
- const candidate = new RTCIceCandidate({
- candidate: arbitraryString,
- sdpMid: 'audio'
- });
-
- assert_equals(candidate.candidate, arbitraryString, 'candidate');
- assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, 'new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid');
-
- test(t => {
- const candidate = new RTCIceCandidate({
- candidate: candidateString,
- sdpMid: 'video',
- sdpMLineIndex: 1,
- usernameFragment: 'test'
- });
-
- assert_equals(candidate.candidate, candidateString, 'candidate');
- assert_equals(candidate.sdpMid, 'video', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 1, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, 'test', 'usernameFragment');
-
- // The following fields should match those in the candidate field
- assert_equals(candidate.foundation, '1905690388', 'foundation');
- assert_equals(candidate.component, 'rtp', 'component');
- assert_equals(candidate.priority, 2113937151, 'priority');
- assert_equals(candidate.address, '192.168.0.1', 'address');
- assert_equals(candidate.protocol, 'udp', 'protocol');
- assert_equals(candidate.port, 58041, 'port');
- assert_equals(candidate.type, 'host', 'type');
- assert_equals(candidate.tcpType, null, 'tcpType');
- assert_equals(candidate.relatedAddress, null, 'relatedAddress');
- assert_equals(candidate.relatedPort, null, 'relatedPort');
- }, 'new RTCIceCandidate({ ... }) with nondefault values for all fields');
-
- test(t => {
- const candidate = new RTCIceCandidate({
- candidate: candidateString2,
- sdpMid: 'video',
- sdpMLineIndex: 1,
- usernameFragment: 'user1'
- });
-
- assert_equals(candidate.candidate, candidateString2, 'candidate');
- assert_equals(candidate.sdpMid, 'video', 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 1, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, 'user1', 'usernameFragment');
-
- // The following fields should match those in the candidate field
- assert_equals(candidate.foundation, '435653019', 'foundation');
- assert_equals(candidate.component, 'rtcp', 'component');
- assert_equals(candidate.priority, 1845501695, 'priority');
- assert_equals(candidate.address, '192.168.0.196', 'address');
- assert_equals(candidate.protocol, 'tcp', 'protocol');
- assert_equals(candidate.port, 4444, 'port');
- assert_equals(candidate.type, 'srflx', 'type');
- assert_equals(candidate.tcpType, 'active', 'tcpType');
- assert_equals(candidate.relatedAddress, 'www.example.com', 'relatedAddress');
- assert_equals(candidate.relatedPort, 22222, 'relatedPort');
- }, 'new RTCIceCandidate({ ... }) with nondefault values for all fields, tcp candidate');
-
- test(t => {
- // sdpMid is not validated in RTCIceCandidate
- const candidate = new RTCIceCandidate({
- sdpMid: arbitraryString
- });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, arbitraryString, 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, 'new RTCIceCandidate({ ... }) with invalid sdpMid');
-
-
- test(t => {
- // Some arbitrary large out of bound line index that practically
- // do not reference any m= line in SDP.
- // However sdpMLineIndex is not validated in RTCIceCandidate
- // and it has no knowledge of the SDP it is associated with.
- const candidate = new RTCIceCandidate({
- sdpMLineIndex: 65535
- });
-
- assert_equals(candidate.candidate, '', 'candidate');
- assert_equals(candidate.sdpMid, null, 'sdpMid');
- assert_equals(candidate.sdpMLineIndex, 65535, 'sdpMLineIndex');
- assert_equals(candidate.usernameFragment, null, 'usernameFragment');
- }, 'new RTCIceCandidate({ ... }) with invalid sdpMLineIndex');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCIceConnectionState and RTCIceCandidatePair</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream = await getNoiseStream({audio:true});
- const [track] = stream.getTracks();
- caller.addTrack(track, stream);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await listenToIceConnected(caller);
-
- const report = await caller.getStats();
- let succeededPairFound = false;
- report.forEach(stats => {
- if (stats.type == 'candidate-pair' && stats.state == 'succeeded')
- succeededPairFound = true;
- });
- assert_true(succeededPairFound, 'A succeeded candidate-pair should exist');
-}, 'On ICE connected, getStats() contains a connected candidate-pair');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCIceTransport</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // createDataChannelPair
- // awaitMessage
-
- /*
- 5.6. RTCIceTransport Interface
- interface RTCIceTransport {
- readonly attribute RTCIceRole role;
- readonly attribute RTCIceComponent component;
- readonly attribute RTCIceTransportState state;
- readonly attribute RTCIceGathererState gatheringState;
- sequence<RTCIceCandidate> getLocalCandidates();
- sequence<RTCIceCandidate> getRemoteCandidates();
- RTCIceCandidatePair? getSelectedCandidatePair();
- RTCIceParameters? getLocalParameters();
- RTCIceParameters? getRemoteParameters();
- ...
- };
-
- getLocalCandidates
- Returns a sequence describing the local ICE candidates gathered for this
- RTCIceTransport and sent in onicecandidate
-
- getRemoteCandidates
- Returns a sequence describing the remote ICE candidates received by this
- RTCIceTransport via addIceCandidate()
-
- getSelectedCandidatePair
- Returns the selected candidate pair on which packets are sent, or null if
- there is no such pair.
-
- getLocalParameters
- Returns the local ICE parameters received by this RTCIceTransport via
- setLocalDescription , or null if the parameters have not yet been received.
-
- getRemoteParameters
- Returns the remote ICE parameters received by this RTCIceTransport via
- setRemoteDescription or null if the parameters have not yet been received.
- */
- function getIceTransportFromSctp(pc) {
- const sctpTransport = pc.sctp;
- assert_true(sctpTransport instanceof RTCSctpTransport,
- 'Expect pc.sctp to be instantiated from RTCSctpTransport');
-
- const dtlsTransport = sctpTransport.transport;
- assert_true(dtlsTransport instanceof RTCDtlsTransport,
- 'Expect sctp.transport to be an RTCDtlsTransport');
-
- const iceTransport = dtlsTransport.iceTransport;
- assert_true(iceTransport instanceof RTCIceTransport,
- 'Expect dtlsTransport.transport to be an RTCIceTransport');
-
- return iceTransport;
- }
-
- function validateCandidates(candidates) {
- assert_greater_than(candidates.length, 0,
- 'Expect at least one ICE candidate returned from get*Candidates()');
-
- for(const candidate of candidates) {
- assert_true(candidate instanceof RTCIceCandidate,
- 'Expect candidate elements to be instance of RTCIceCandidate');
- }
- }
-
- function validateCandidateParameter(param) {
- assert_not_equals(param, null,
- 'Expect candidate parameter to be non-null after data channels are connected');
-
- assert_equals(typeof param.usernameFragment, 'string',
- 'Expect param.usernameFragment to be set with string value');
- assert_equals(typeof param.password, 'string',
- 'Expect param.password to be set with string value');
- }
-
- function validateConnectedIceTransport(iceTransport) {
- const { state, gatheringState, role, component } = iceTransport;
-
- assert_true(role === 'controlling' || role === 'controlled',
- 'Expect RTCIceRole to be either controlling or controlled, found ' + role);
-
- assert_true(component === 'rtp' || component === 'rtcp',
- 'Expect RTCIceComponent to be either rtp or rtcp');
-
- assert_true(state === 'connected' || state === 'completed',
- 'Expect ICE transport to be in connected or completed state after data channels are connected');
-
- assert_true(gatheringState === 'gathering' || gatheringState === 'completed',
- 'Expect ICE transport to be in gathering or completed gatheringState after data channels are connected');
-
- validateCandidates(iceTransport.getLocalCandidates());
- validateCandidates(iceTransport.getRemoteCandidates());
-
- const candidatePair = iceTransport.getSelectedCandidatePair();
- assert_not_equals(candidatePair, null,
- 'Expect selected candidate pair to be non-null after ICE transport is connected');
-
- assert_true(candidatePair.local instanceof RTCIceCandidate,
- 'Expect candidatePair.local to be instance of RTCIceCandidate');
-
- assert_true(candidatePair.remote instanceof RTCIceCandidate,
- 'Expect candidatePair.remote to be instance of RTCIceCandidate');
-
- validateCandidateParameter(iceTransport.getLocalParameters());
- validateCandidateParameter(iceTransport.getRemoteParameters());
- }
-
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('');
-
- // setRemoteDescription(answer) without the other peer
- // setting answer it's localDescription
- return pc1.createOffer()
- .then(offer =>
- pc1.setLocalDescription(offer)
- .then(() => pc2.setRemoteDescription(offer))
- .then(() => pc2.createAnswer()))
- .then(answer => pc1.setRemoteDescription(answer))
- .then(() => {
- const iceTransport = getIceTransportFromSctp(pc1);
-
- assert_array_equals(iceTransport.getRemoteCandidates(), [],
- 'Expect iceTransport to not have any remote candidate');
-
- assert_equals(iceTransport.getSelectedCandidatePair(), null,
- 'Expect selectedCandidatePair to be null');
- });
- }, 'Unconnected iceTransport should have empty remote candidates and selected pair');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const signalingStates = [];
- pc.onsignalingstatechange = ev => signalingStates.push(pc.signalingState);
- pc.addTransceiver('audio', {direction:'recvonly'});
- const offer = await pc.createOffer();
- const sldPromise = pc.setLocalDescription(offer);
- const srdPromise = pc.setRemoteDescription(offer);
- await Promise.all([sldPromise, srdPromise]);
- assert_array_equals(signalingStates,
- ['have-local-offer','stable','have-remote-offer']);
-}, 'setLocalDescription and setRemoteDescription are not racy');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection addTrack does not deadlock</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // This test sets up two peer connections using a sequence of operations
- // that triggered a deadlock in Chrome. See https://crbug.com/736725.
- // If a deadlock is introduced again, this test times out.
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const stream = await getNoiseStream(
- {audio: false, video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const videoTrack = stream.getVideoTracks()[0];
- pc1.addTrack(videoTrack, stream);
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const srdPromise = pc2.setRemoteDescription(offer);
- pc2.addTrack(videoTrack, stream);
- // The deadlock encountered in https://crbug.com/736725 occured here.
- await srdPromise;
- await pc2.createAnswer();
- }, 'RTCPeerConnection addTrack does not deadlock.');
-</script>
+++ /dev/null
-<!doctype html>
-<meta name="timeout" content="long">
-<title>Test RTCPeerConnection.prototype.addIceCandidate</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
-// This test may be flaky, so it's in its own file.
-// The test belongs in RTCPeerConnection-addIceCandidate.
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const transceiver = pc1.addTransceiver('video');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOffer(pc1, pc2);
- const answer = await pc2.createAnswer();
- // Note that sequence of the following two calls is critical
- // for test stability.
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- await waitForState(transceiver.sender.transport, 'connected');
-}, 'Candidates are added dynamically; connection should work');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const transceiver = pc1.addTransceiver('video');
-
- let candidates1to2 = [];
- let candidates2to1 = [];
- pc1.onicecandidate = e => candidates1to2.push(e.candidate);
- pc2.onicecandidate = e => candidates2to1.push(e.candidate);
- const pc2GatheredCandidates = new Promise((resolve) => {
- pc2.addEventListener('icegatheringstatechange', () => {
- if (pc2.iceGatheringState == 'complete') {
- resolve();
- }
- });
- });
- await exchangeOffer(pc1, pc2);
- let answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- await pc2GatheredCandidates;
- // Add candidates to pc1, ensuring that it goes to "connecting" state before "connected".
- // We do not iterate/await because repeatedly awaiting while we serially add
- // the candidates opens the opportunity to miss the 'connecting' transition.
- const addCandidatesDone = Promise.all(candidates2to1.map(c => pc1.addIceCandidate(c)));
- await waitForState(transceiver.sender.transport, 'connecting');
- await addCandidatesDone;
- await waitForState(transceiver.sender.transport, 'connected');
-}, 'Candidates are added at PC1; connection should work');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const transceiver = pc1.addTransceiver('video');
-
- let candidates1to2 = [];
- let candidates2to1 = [];
- pc1.onicecandidate = e => candidates1to2.push(e.candidate);
- pc2.onicecandidate = e => candidates2to1.push(e.candidate);
- const pc1GatheredCandidates = new Promise((resolve) => {
- pc1.addEventListener('icegatheringstatechange', () => {
- if (pc1.iceGatheringState == 'complete') {
- resolve();
- }
- });
- });
- await exchangeOffer(pc1, pc2);
- let answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- await pc1GatheredCandidates;
- // Add candidates to pc2
- // We do not iterate/await because repeatedly awaiting while we serially add
- // the candidates opens the opportunity to miss the ICE state transitions.
- await Promise.all(candidates1to2.map(c => pc2.addIceCandidate(c)));
- await waitForState(transceiver.sender.transport, 'connected');
-}, 'Candidates are added at PC2; connection should work');
-
-</script>
+++ /dev/null
-<!doctype html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-
-'use strict';
-
-// In this test, the promises should resolve in the execution order
-// (setLocalDescription, setLocalDescription, addIceCandidate) as is ensured by
-// the Operations Chain; if an operation is pending, executing another operation
-// will queue it. This test will fail if an Operations Chain is not implemented,
-// but it gives the implementation some slack: it only ensures that
-// addIceCandidate() is not resolved first, allowing timing issues in resolving
-// promises where the test still passes even if addIceCandidate() is resolved
-// *before* the second setLocalDescription().
-//
-// This test covers Chrome issue (https://crbug.com/1019222), but does not
-// require setLocalDescription-promises to resolve immediately which is another
-// Chrome bug (https://crbug.com/1019232). The true order is covered by the next
-// test.
-// TODO(https://crbug.com/1019232): Delete this test when the next test passes
-// in Chrome.
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- caller.addTransceiver('audio');
-
- const candidatePromise = new Promise(resolve => {
- caller.onicecandidate = e => resolve(e.candidate);
- });
- await caller.setLocalDescription(await caller.createOffer());
- await callee.setRemoteDescription(caller.localDescription);
- const candidate = await candidatePromise;
-
- // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
- // without performing await between the calls.
- const pendingPromises = [];
- const resolveOrder = [];
- pendingPromises.push(callee.setLocalDescription().then(() => {
- resolveOrder.push('setLocalDescription 1');
- }));
- pendingPromises.push(callee.setLocalDescription().then(() => {
- resolveOrder.push('setLocalDescription 2');
- }));
- pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
- resolveOrder.push('addIceCandidate');
- }));
- await Promise.all(pendingPromises);
-
- assert_equals(resolveOrder[0], 'setLocalDescription 1');
-}, 'addIceCandidate is not resolved first if 2x setLocalDescription ' +
- 'operations are pending');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- caller.addTransceiver('audio');
-
- const candidatePromise = new Promise(resolve => {
- caller.onicecandidate = e => resolve(e.candidate);
- });
- await caller.setLocalDescription(await caller.createOffer());
- await callee.setRemoteDescription(caller.localDescription);
- const candidate = await candidatePromise;
-
- // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
- // without performing await between the calls.
- const pendingPromises = [];
- const resolveOrder = [];
- pendingPromises.push(callee.setLocalDescription().then(() => {
- resolveOrder.push('setLocalDescription 1');
- }));
- pendingPromises.push(callee.setLocalDescription().then(() => {
- resolveOrder.push('setLocalDescription 2');
- }));
- pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
- resolveOrder.push('addIceCandidate');
- }));
- await Promise.all(pendingPromises);
-
- // This test verifies that both issues described in https://crbug.com/1019222
- // and https://crbug.com/1019232 are fixed. If this test passes in Chrome, the
- // ICE candidate exchange issues described in
- // https://github.com/web-platform-tests/wpt/issues/19866 should be resolved.
- assert_array_equals(
- resolveOrder,
- ['setLocalDescription 1', 'setLocalDescription 2', 'addIceCandidate']);
-}, 'addIceCandidate and setLocalDescription are resolved in the correct ' +
- 'order, as defined by the operations chain specification');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- caller.addTransceiver('audio');
- let events = [];
- let pendingPromises = [];
-
- const onCandidatePromise = new Promise(resolve => {
- caller.onicecandidate = () => {
- events.push('candidate generated');
- resolve();
- }
- });
- pendingPromises.push(onCandidatePromise);
- pendingPromises.push(caller.setLocalDescription().then(() => {
- events.push('setLocalDescription');
- }));
- await Promise.all(pendingPromises);
- assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
-}, 'onicecandidate fires after resolving setLocalDescription in offerer');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- caller.addTransceiver('audio');
- let events = [];
- let pendingPromises = [];
-
- caller.onicecandidate = (ev) => {
- if (ev.candidate) {
- callee.addIceCandidate(ev.candidate);
- }
- }
- const offer = await caller.createOffer();
- const onCandidatePromise = new Promise(resolve => {
- callee.onicecandidate = () => {
- events.push('candidate generated');
- resolve();
- }
- });
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- pendingPromises.push(onCandidatePromise);
- pendingPromises.push(callee.setLocalDescription(answer).then(() => {
- events.push('setLocalDescription');
- }));
- await Promise.all(pendingPromises);
- assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
-}, 'onicecandidate fires after resolving setLocalDescription in answerer');
-
-</script>
+++ /dev/null
-<!doctype html>
-<title>Test RTCPeerConnection.prototype.addIceCandidate</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // SDP copied from JSEP Example 7.1
- // It contains two media streams with different ufrags
- // to test if candidate is added to the correct stream
- const sdp = `v=0
-o=- 4962303333179871722 1 IN IP4 0.0.0.0
-s=-
-t=0 0
-a=ice-options:trickle
-a=group:BUNDLE a1 v1
-a=group:LS a1 v1
-m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
-c=IN IP4 203.0.113.100
-a=mid:a1
-a=sendrecv
-a=rtpmap:96 opus/48000/2
-a=rtpmap:0 PCMU/8000
-a=rtpmap:8 PCMA/8000
-a=rtpmap:97 telephone-event/8000
-a=rtpmap:98 telephone-event/48000
-a=maxptime:120
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
-a=ice-ufrag:ETEn
-a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10101 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-m=video 10102 UDP/TLS/RTP/SAVPF 100 101
-c=IN IP4 203.0.113.100
-a=mid:v1
-a=sendrecv
-a=rtpmap:100 VP8/90000
-a=rtpmap:101 rtx/90000
-a=fmtp:101 apt=100
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=rtcp-fb:100 ccm fir
-a=rtcp-fb:100 nack
-a=rtcp-fb:100 nack pli
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
-a=ice-ufrag:BGKk
-a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10103 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-`;
-
- const sessionDesc = { type: 'offer', sdp };
-
- // valid candidate attributes
- const sdpMid1 = 'a1';
- const sdpMLineIndex1 = 0;
- const usernameFragment1 = 'ETEn';
-
- const sdpMid2 = 'v1';
- const sdpMLineIndex2 = 1;
- const usernameFragment2 = 'BGKk';
-
- const mediaLine1 = 'm=audio';
- const mediaLine2 = 'm=video';
-
- const candidateStr1 = 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
- const candidateStr2 = 'candidate:1 2 udp 2113929470 203.0.113.100 10101 typ host';
- const invalidCandidateStr = '(Invalid) candidate \r\n string';
-
- const candidateLine1 = `a=${candidateStr1}`;
- const candidateLine2 = `a=${candidateStr2}`;
- const endOfCandidateLine = 'a=end-of-candidates';
-
- // Copied from MDN
- function escapeRegExp(string) {
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
- }
-
- function is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
- const line1 = escapeRegExp(beforeMediaLine);
- const line2 = escapeRegExp(candidateLine);
- const line3 = escapeRegExp(afterMediaLine);
-
- const regex = new RegExp(`${line1}[^]+${line2}[^]+${line3}`);
- return regex.test(sdp);
- }
-
- // Check that a candidate line is found after the first media line
- // but before the second, i.e. it belongs to the first media stream
- function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
- assert_true(is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine),
- `Expect candidate line to be found between media lines ${beforeMediaLine} and ${afterMediaLine}`);
- }
-
- // Check that a candidate line is found after the second media line
- // i.e. it belongs to the second media stream
- function is_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
- const line1 = escapeRegExp(beforeMediaLine);
- const line2 = escapeRegExp(candidateLine);
-
- const regex = new RegExp(`${line1}[^]+${line2}`);
-
- return regex.test(sdp);
- }
-
- function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
- assert_true(is_candidate_line_after(sdp, beforeMediaLine, candidateLine),
- `Expect candidate line to be found after media line ${beforeMediaLine}`);
- }
-
- /*
- 4.4.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.
- */
-
- /*
- Success cases
- */
-
- // All of these should work, because all of these end up being equivalent to the
- // same thing; an end-of-candidates signal for all levels/mids/ufrags.
- [
- // This is just the default. Everything else here is equivalent to this.
- {
- candidate: '',
- sdpMid: null,
- sdpMLineIndex: null,
- usernameFragment: undefined
- },
- // The arg is optional, so when passing undefined we'll just get the default
- undefined,
- // The arg is optional, but not nullable, so we get the default again
- null,
- // Members in the dictionary take their default values
- {}
- ].forEach(init => {
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- await pc.setRemoteDescription(sessionDesc);
- await pc.addIceCandidate(init);
- }, `addIceCandidate(${JSON.stringify(init)}) works`);
- });
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- await pc.setRemoteDescription(sessionDesc)
- await pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- });
- assert_candidate_line_after(pc.remoteDescription.sdp,
- mediaLine1, candidateStr1);
- }, 'Add ICE candidate after setting remote description should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate(new RTCIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- })));
- }, 'Add ICE candidate with RTCIceCandidate should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1 }));
- }, 'Add candidate with only valid sdpMid should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate(new RTCIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1 })));
- }, 'Add candidate with only valid sdpMid and RTCIceCandidate should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMLineIndex: sdpMLineIndex1 }));
- }, 'Add candidate with only valid sdpMLineIndex should succeed');
-
- /*
- 4.4.2. addIceCandidate
- 4.6.2. If candidate is applied successfully, the user agent MUST queue
- a task that runs the following steps:
- 2. If connection.pendingRemoteDescription is non-null, and represents
- the ICE generation for which candidate was processed, add
- candidate to connection.pendingRemoteDescription.
- 3. If connection.currentRemoteDescription is non-null, and represents
- the ICE generation for which candidate was processed, add
- candidate to connection.currentRemoteDescription.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- }))
- .then(() => {
- assert_candidate_line_between(pc.remoteDescription.sdp,
- mediaLine1, candidateLine1, mediaLine2);
- });
- }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr2,
- sdpMid: sdpMid2,
- sdpMLineIndex: sdpMLineIndex2,
- usernameFragment: usernameFragment2
- }))
- .then(() => {
- assert_candidate_line_after(pc.remoteDescription.sdp,
- mediaLine2, candidateLine2);
- });
- }, 'addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragment: null
- }))
- .then(() => {
- assert_candidate_line_between(pc.remoteDescription.sdp,
- mediaLine1, candidateLine1, mediaLine2);
- });
- }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- }))
- .then(() => pc.addIceCandidate({
- candidate: candidateStr2,
- sdpMid: sdpMid2,
- sdpMLineIndex: sdpMLineIndex2,
- usernameFragment: usernameFragment2
- }))
- .then(() => {
- assert_candidate_line_between(pc.remoteDescription.sdp,
- mediaLine1, candidateLine1, mediaLine2);
-
- assert_candidate_line_after(pc.remoteDescription.sdp,
- mediaLine2, candidateLine2);
- });
- }, 'Adding multiple candidates should add candidates to their corresponding media stream');
-
- /*
- 4.4.2. addIceCandidate
- 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
- with a newly created TypeError.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_js(t, TypeError,
- pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: null,
- sdpMLineIndex: null
- })));
- }, 'Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- await pc.setRemoteDescription(sessionDesc);
- promise_rejects_js(t, TypeError,
- pc.addIceCandidate({candidate: candidateStr1}));
- }, 'addIceCandidate with a candidate and neither sdpMid nor sdpMLineIndex should reject with TypeError');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_js(t, TypeError,
- pc.addIceCandidate({
- candidate: candidateStr1
- })));
- }, 'Add candidate with only valid candidate string should reject with TypeError');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_js(t, TypeError,
- pc.addIceCandidate({
- candidate: invalidCandidateStr,
- sdpMid: null,
- sdpMLineIndex: null
- })));
- }, 'Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError');
-
- /*
- 4.4.2. addIceCandidate
- 4.3. If candidate.sdpMid is not null, run the following steps:
- 1. If candidate.sdpMid is not equal to the mid of any media
- description in remoteDescription , reject p with a newly
- created OperationError and abort these steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_dom(t, 'OperationError',
- pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: 'invalid',
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- })));
- }, 'Add candidate with invalid sdpMid should reject with OperationError');
-
- /*
- 4.4.2. addIceCandidate
- 4.4. Else, if candidate.sdpMLineIndex is not null, run the following
- steps:
- 1. If candidate.sdpMLineIndex is equal to or larger than the
- number of media descriptions in remoteDescription , reject p
- with a newly created OperationError and abort these steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_dom(t, 'OperationError',
- pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMLineIndex: 2,
- usernameFragement: usernameFragment1
- })));
- }, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
-
- // There is an "Else" for the statement:
- // "Else, if candidate.sdpMLineIndex is not null, ..."
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr1,
- sdpMid: sdpMid1,
- sdpMLineIndex: 2,
- usernameFragement: usernameFragment1
- }));
- }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() => pc.addIceCandidate({
- candidate: candidateStr2,
- sdpMid: sdpMid2,
- sdpMLineIndex: sdpMLineIndex2,
- usernameFragment: null
- }))
- .then(() => {
- assert_candidate_line_after(pc.remoteDescription.sdp,
- mediaLine2, candidateLine2);
- });
- }, 'Add candidate for media stream 2 with null usernameFragment should succeed');
-
- /*
- 4.4.2. addIceCandidate
- 4.6.1. If candidate could not be successfully added the user agent MUST
- queue a task that runs the following steps:
- 2. Reject p with a DOMException object whose name attribute has
- the value OperationError and abort these steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(sessionDesc)
- .then(() =>
- promise_rejects_dom(t, 'OperationError',
- pc.addIceCandidate({
- candidate: invalidCandidateStr,
- sdpMid: sdpMid1,
- sdpMLineIndex: sdpMLineIndex1,
- usernameFragement: usernameFragment1
- })));
- }, 'Add candidate with invalid candidate string should reject with OperationError');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.addTrack</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="../resources/testdriver.js"></script>
-<script src="../resources/testdriver-vendor.js"></script>
-<script src="support/permission-helper.js"></script>
-<script src="support/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:
- // getNoiseStream()
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
- partial interface RTCPeerConnection {
- ...
- sequence<RTCRtpSender> getSenders();
- sequence<RTCRtpReceiver> getReceivers();
- sequence<RTCRtpTransceiver> getTransceivers();
- RTCRtpSender addTrack(MediaStreamTrack track,
- MediaStream... streams);
- RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
- optional RTCRtpTransceiverInit init);
- };
-
- Note
- While addTrack checks if the MediaStreamTrack given as an argument is
- already being sent to avoid sending the same MediaStreamTrack twice,
- the other ways do not, allowing the same MediaStreamTrack to be sent
- several times simultaneously.
- */
-
- /*
- 5.1. addTrack
- 4. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- pc.close();
- assert_throws_dom('InvalidStateError', () => pc.addTrack(track, stream))
- }, 'addTrack when pc is closed should throw InvalidStateError');
-
- /*
- 5.1. addTrack
- 8. If sender is null, run the following steps:
- 1. Create an RTCRtpSender with track and streams and let sender be
- the result.
- 2. Create an RTCRtpReceiver with track.kind as kind and let receiver
- be the result.
- 3. Create an RTCRtpTransceiver with sender and receiver and let
- transceiver be the result.
- 4. Add transceiver to connection's set of transceivers.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const sender = pc.addTrack(track);
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_equals(sender.track, track,
- `Expect sender's track to be the added track`);
-
- const transceivers = pc.getTransceivers();
- assert_equals(transceivers.length, 1,
- 'Expect only one transceiver with sender added');
-
- const [transceiver] = transceivers;
- assert_equals(transceiver.sender, sender);
-
- assert_array_equals([sender], pc.getSenders(),
- 'Expect only one sender with given track added');
-
- const { receiver } = transceiver;
- assert_equals(receiver.track.kind, 'audio');
- assert_array_equals([transceiver.receiver], pc.getReceivers(),
- 'Expect only one receiver associated with transceiver added');
- }, 'addTrack with single track argument and no stream should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const sender = pc.addTrack(track, stream);
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_equals(sender.track, track,
- `Expect sender's track to be the added track`);
- }, 'addTrack with single track argument and single stream should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const stream2 = new MediaStream([track]);
- const sender = pc.addTrack(track, stream, stream2);
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_equals(sender.track, track,
- `Expect sender's track to be the added track`);
- }, 'addTrack with single track argument and multiple streams should succeed');
-
- /*
- 5.1. addTrack
- 5. Let senders be the result of executing the CollectSenders algorithm.
- If an RTCRtpSender for track already exists in senders, throw an
- InvalidAccessError.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- pc.addTrack(track, stream);
- assert_throws_dom('InvalidAccessError', () => pc.addTrack(track, stream));
- }, 'Adding the same track multiple times should throw InvalidAccessError');
-
- /*
- 5.1. addTrack
- 6. The steps below describe how to determine if an existing sender can
- be reused.
-
- If any RTCRtpSender object in senders matches all the following
- criteria, let sender be that object, or null otherwise:
- - The sender's track is null.
- - The transceiver kind of the RTCRtpTransceiver, associated with
- the sender, matches track's kind.
- - The sender has never been used to send. More precisely, the
- RTCRtpTransceiver associated with the sender has never had a
- currentDirection of sendrecv or sendonly.
- 7. If sender is not null, run the following steps to use that sender:
- 1. Set sender.track to track.
- 3. Enable sending direction on the RTCRtpTransceiver associated
- with sender.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio', { direction: 'recvonly' });
- assert_equals(transceiver.sender.track, null);
- assert_equals(transceiver.direction, 'recvonly');
-
- await setMediaPermission("granted", ["microphone"]);
- const stream = await navigator.mediaDevices.getUserMedia({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track);
-
- assert_equals(sender, transceiver.sender);
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'sendrecv');
- assert_array_equals([sender], pc.getSenders());
- }, 'addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.sender.track, null);
- assert_equals(transceiver.direction, 'sendrecv');
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track);
-
- assert_equals(sender.track, track);
- assert_equals(sender, transceiver.sender);
- }, 'addTrack with existing sender that has not been used to send should reuse the sender');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = caller.addTransceiver(track);
- {
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- }
- assert_equals(transceiver.currentDirection, 'sendonly');
-
- caller.removeTrack(transceiver.sender);
- {
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- }
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, 'inactive');
-
- // |transceiver.sender| is currently not used for sending, but it should not
- // be reused because it has been used for sending before.
- const sender = caller.addTrack(track);
- assert_true(sender != null);
- assert_not_equals(sender, transceiver.sender);
- }, 'addTrack with existing sender that has been used to send should create new sender');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('video', { direction: 'recvonly' });
- assert_equals(transceiver.sender.track, null);
- assert_equals(transceiver.direction, 'recvonly');
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track);
-
- assert_equals(sender.track, track);
- assert_not_equals(sender, transceiver.sender);
-
- const senders = pc.getSenders();
- assert_equals(senders.length, 2,
- 'Expect 2 senders added to connection');
-
- assert_true(senders.includes(sender),
- 'Expect senders list to include sender');
-
- assert_true(senders.includes(transceiver.sender),
- `Expect senders list to include first transceiver's sender`);
- }, 'addTrack with existing sender with null track, different kind, and recvonly direction should create new sender');
-
- /*
- TODO
- 5.1. addTrack
- 3. Let streams be a list of MediaStream objects constructed from the
- method's remaining arguments, or an empty list if the method was
- called with a single argument.
- 6. The steps below describe how to determine if an existing sender can
- be reused. Doing so will cause future calls to createOffer and
- createAnswer to mark the corresponding media description as sendrecv
- or sendonly and add the MSID of the track added, as defined in [JSEP]
- (section 5.2.2. and section 5.3.2.).
-
- Non-Testable
- 5.1. addTrack
- 7. If sender is not null, run the following steps to use that sender:
- 2. Set sender's [[associated MediaStreams]] to streams.
-
- Tested in RTCPeerConnection-onnegotiationneeded.html:
- 5.1. addTrack
- 10. Update the negotiation-needed flag for connection.
-
- */
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = caller.addTransceiver(track);
- // Note that this test doesn't process canididates.
- {
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- }
- assert_equals(transceiver.currentDirection, 'sendonly');
- await waitForIceGatheringState(caller, ['complete']);
- await waitForIceGatheringState(callee, ['complete']);
-
- const second_stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => second_stream.getTracks().forEach(track => track.stop()));
- // There may be callee candidates in flight. It seems that waiting
- // for a createOffer() is enough time to let them complete processing.
- // TODO(https://crbug.com/webrtc/13095): Fix bug and remove.
- await caller.createOffer();
-
- const [second_track] = second_stream.getTracks();
- caller.onicecandidate = t.unreached_func(
- 'No caller candidates should be generated.');
- callee.onicecandidate = t.unreached_func(
- 'No callee candidates should be generated.');
- caller.addTrack(second_track);
- {
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- }
- // Check that we're bundled.
- const [first_transceiver, second_transceiver] = caller.getTransceivers();
- assert_equals(first_transceiver.transport, second_transceiver.transport);
-
- }, 'Adding more tracks does not generate more candidates if bundled');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- pc1.addTrack(track);
- const offer = await pc1.createOffer();
- // We do not await here; we want to ensure that the transceiver this creates
- // is untouched by addTrack, and that addTrack creates _another_ transceiver
- const srdPromise = pc2.setRemoteDescription(offer);
-
- const sender = pc2.addTrack(track);
-
- await srdPromise;
-
- assert_equals(pc2.getTransceivers().length, 1, "Should have 1 transceiver");
- assert_equals(pc2.getTransceivers()[0].sender, sender, "The transceiver should be the one added by addTrack");
- }, 'Calling addTrack while sRD(offer) is pending should allow the new remote transceiver to be the same one that addTrack creates');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('video');
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const offer = await pc1.createOffer();
- const srdPromise = pc2.setRemoteDescription(offer);
- assert_equals(pc2.getTransceivers().length, 0);
- pc2.addTrack(track);
- assert_equals(pc2.getTransceivers().length, 1);
- const transceiver0 = pc2.getTransceivers()[0];
- assert_equals(transceiver0.mid, null);
- await srdPromise;
- assert_equals(pc2.getTransceivers().length, 2);
- const transceiver1 = pc2.getTransceivers()[1];
- assert_equals(transceiver0.mid, null);
- assert_not_equals(transceiver1.mid, null);
- }, 'When addTrack is called while sRD is in progress, and both addTrack and sRD add a transceiver of different media types, the addTrack transceiver should come first, and then the sRD transceiver.');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.addTransceiver</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://rawgit.com/w3c/webrtc-pc/cc8d80f455b86c8041d63bceb8b457f45c72aa89/webrtc.html
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
-
- partial interface RTCPeerConnection {
- sequence<RTCRtpSender> getSenders();
- sequence<RTCRtpReceiver> getReceivers();
- sequence<RTCRtpTransceiver> getTransceivers();
- RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
- optional RTCRtpTransceiverInit init);
- ...
- };
-
- dictionary RTCRtpTransceiverInit {
- RTCRtpTransceiverDirection direction = "sendrecv";
- sequence<MediaStream> streams;
- sequence<RTCRtpEncodingParameters> sendEncodings;
- };
-
- enum RTCRtpTransceiverDirection {
- "sendrecv",
- "sendonly",
- "recvonly",
- "inactive"
- };
-
- 5.2. RTCRtpSender Interface
-
- interface RTCRtpSender {
- readonly attribute MediaStreamTrack? track;
- ...
- };
-
- 5.3. RTCRtpReceiver Interface
-
- interface RTCRtpReceiver {
- readonly attribute MediaStreamTrack track;
- ...
- };
-
- 5.4. RTCRtpTransceiver Interface
-
- interface RTCRtpTransceiver {
- readonly attribute DOMString? mid;
- [SameObject]
- readonly attribute RTCRtpSender sender;
- [SameObject]
- readonly attribute RTCRtpReceiver receiver;
- readonly attribute boolean stopped;
- readonly attribute RTCRtpTransceiverDirection direction;
- readonly attribute RTCRtpTransceiverDirection? currentDirection;
- ...
- };
-
- Note
- While addTrack checks if the MediaStreamTrack given as an argument is
- already being sent to avoid sending the same MediaStreamTrack twice,
- the other ways do not, allowing the same MediaStreamTrack to be sent
- several times simultaneously.
- */
-
- /*
- 5.1. addTransceiver
- 3. If the first argument is a string, let it be kind and run the following steps:
- 1. If kind is not a legal MediaStreamTrack kind, throw a TypeError.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_idl_attribute(pc, 'addTransceiver');
- assert_throws_js(TypeError, () => pc.addTransceiver('invalid'));
- }, 'addTransceiver() with string argument as invalid kind should throw TypeError');
-
- /*
- 5.1. addTransceiver
- The initial value of mid is null.
-
- 3. If the dictionary argument is present, let direction be the value of the
- direction member. Otherwise let direction be sendrecv.
- 4. If the first argument is a string, let it be kind and run the following steps:
- 2. Let track be null.
- 8. Create an RTCRtpSender with track, streams and sendEncodings and let
- sender be the result.
- 9. Create an RTCRtpReceiver with kind and let receiver be the result.
- 10. Create an RTCRtpTransceiver with sender, receiver and direction, and let
- transceiver be the result.
- 11. Add transceiver to connection's set of transceivers.
-
- 5.2. RTCRtpSender Interface
- Create an RTCRtpSender
- 2. Set sender.track to track.
-
- 5.3. RTCRtpReceiver Interface
- Create an RTCRtpReceiver
- 2. Let track be a new MediaStreamTrack object [GETUSERMEDIA]. The source of
- track is a remote source provided by receiver.
- 3. Initialize track.kind to kind.
- 5. Initialize track.label to the result of concatenating the string "remote "
- with kind.
- 6. Initialize track.readyState to live.
- 7. Initialize track.muted to true.
- 8. Set receiver.track to track.
-
- 5.4. RTCRtpTransceiver Interface
- Create an RTCRtpTransceiver
- 2. Set transceiver.sender to sender.
- 3. Set transceiver.receiver to receiver.
- 4. Let transceiver have a [[Direction]] internal slot, initialized to direction.
- 5. Let transceiver have a [[CurrentDirection]] internal slot, initialized
- to null.
- 6. Set transceiver.stopped to false.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_idl_attribute(pc, 'addTransceiver');
-
- const transceiver = pc.addTransceiver('audio');
- assert_true(transceiver instanceof RTCRtpTransceiver,
- 'Expect transceiver to be instance of RTCRtpTransceiver');
-
- assert_equals(transceiver.mid, null);
- assert_equals(transceiver.stopped, false);
- assert_equals(transceiver.direction, 'sendrecv');
- assert_equals(transceiver.currentDirection, null);
-
- assert_array_equals([transceiver], pc.getTransceivers(),
- `Expect added transceiver to be the only element in connection's list of transceivers`);
-
- const sender = transceiver.sender;
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_equals(sender.track, null);
-
- assert_array_equals([sender], pc.getSenders(),
- `Expect added sender to be the only element in connection's list of senders`);
-
- const receiver = transceiver.receiver;
- assert_true(receiver instanceof RTCRtpReceiver,
- 'Expect receiver to be instance of RTCRtpReceiver');
-
- const track = receiver.track;
- assert_true(track instanceof MediaStreamTrack,
- 'Expect receiver.track to be instance of MediaStreamTrack');
-
- assert_equals(track.kind, 'audio');
- assert_equals(track.readyState, 'live');
- assert_equals(track.muted, true);
-
- assert_array_equals([receiver], pc.getReceivers(),
- `Expect added receiver to be the only element in connection's list of receivers`);
-
- }, `addTransceiver('audio') should return an audio transceiver`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_idl_attribute(pc, 'addTransceiver');
-
- const transceiver = pc.addTransceiver('video');
- assert_true(transceiver instanceof RTCRtpTransceiver,
- 'Expect transceiver to be instance of RTCRtpTransceiver');
-
- assert_equals(transceiver.mid, null);
- assert_equals(transceiver.stopped, false);
- assert_equals(transceiver.direction, 'sendrecv');
-
- assert_array_equals([transceiver], pc.getTransceivers(),
- `Expect added transceiver to be the only element in connection's list of transceivers`);
-
- const sender = transceiver.sender;
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_equals(sender.track, null);
-
- assert_array_equals([sender], pc.getSenders(),
- `Expect added sender to be the only element in connection's list of senders`);
-
- const receiver = transceiver.receiver;
- assert_true(receiver instanceof RTCRtpReceiver,
- 'Expect receiver to be instance of RTCRtpReceiver');
-
- const track = receiver.track;
- assert_true(track instanceof MediaStreamTrack,
- 'Expect receiver.track to be instance of MediaStreamTrack');
-
- assert_equals(track.kind, 'video');
- assert_equals(track.readyState, 'live');
- assert_equals(track.muted, true);
-
- assert_array_equals([receiver], pc.getReceivers(),
- `Expect added receiver to be the only element in connection's list of receivers`);
-
- }, `addTransceiver('video') should return a video transceiver`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' });
- assert_equals(transceiver.direction, 'sendonly');
- }, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio', { direction: 'inactive' });
- assert_equals(transceiver.direction, 'inactive');
- }, `addTransceiver() with direction inactive should have result transceiver.direction be the same`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_idl_attribute(pc, 'addTransceiver');
- assert_throws_js(TypeError, () =>
- pc.addTransceiver('audio', { direction: 'invalid' }));
- }, `addTransceiver() with invalid direction should throw TypeError`);
-
- /*
- 5.1. addTransceiver
- 5. If the first argument is a MediaStreamTrack , let it be track and let
- kind be track.kind.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track);
- const { sender, receiver } = transceiver;
-
- assert_true(sender instanceof RTCRtpSender,
- 'Expect sender to be instance of RTCRtpSender');
-
- assert_true(receiver instanceof RTCRtpReceiver,
- 'Expect receiver to be instance of RTCRtpReceiver');
-
- assert_equals(sender.track, track,
- 'Expect sender.track should be the track that is added');
-
- const receiverTrack = receiver.track;
- assert_true(receiverTrack instanceof MediaStreamTrack,
- 'Expect receiver.track to be instance of MediaStreamTrack');
-
- assert_equals(receiverTrack.kind, 'audio',
- `receiver.track should have the same kind as added track's kind`);
-
- assert_equals(receiverTrack.readyState, 'live');
- assert_equals(receiverTrack.muted, true);
-
- assert_array_equals([transceiver], pc.getTransceivers(),
- `Expect added transceiver to be the only element in connection's list of transceivers`);
-
- assert_array_equals([sender], pc.getSenders(),
- `Expect added sender to be the only element in connection's list of senders`);
-
- assert_array_equals([receiver], pc.getReceivers(),
- `Expect added receiver to be the only element in connection's list of receivers`);
-
- }, 'addTransceiver(track) should have result with sender.track be given track');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver1 = pc.addTransceiver(track);
- const transceiver2 = pc.addTransceiver(track);
-
- assert_not_equals(transceiver1, transceiver2);
-
- const sender1 = transceiver1.sender;
- const sender2 = transceiver2.sender;
-
- assert_not_equals(sender1, sender2);
- assert_equals(transceiver1.sender.track, track);
- assert_equals(transceiver2.sender.track, track);
-
- const transceivers = pc.getTransceivers();
- assert_equals(transceivers.length, 2);
- assert_true(transceivers.includes(transceiver1));
- assert_true(transceivers.includes(transceiver2));
-
- const senders = pc.getSenders();
- assert_equals(senders.length, 2);
- assert_true(senders.includes(sender1));
- assert_true(senders.includes(sender2));
-
- }, 'addTransceiver(track) multiple times should create multiple transceivers');
-
- /*
- 5.1. addTransceiver
- 6. Verify that each rid value in sendEncodings is composed only of
- case-sensitive alphanumeric characters (a-z, A-Z, 0-9) up to a maximum
- of 16 characters. If one of the RIDs does not meet these requirements,
- throw a TypeError.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- assert_idl_attribute(pc, 'addTransceiver');
-
- assert_throws_js(TypeError, () =>
- pc.addTransceiver('audio', {
- sendEncodings: [{
- rid: '@Invalid!'
- }]
- }));
- }, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError');
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- assert_idl_attribute(pc, 'addTransceiver');
-
- assert_throws_js(TypeError, () =>
- pc.addTransceiver('audio', {
- sendEncodings: [{
- rid: 'a'.repeat(17)
- }]
- }));
- }, 'addTransceiver() with rid longer than 16 characters should throw TypeError');
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('audio', {
- sendEncodings: [{
- rid: 'foo'
- }]
- });
- }, `addTransceiver() with valid rid value should succeed`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio', {
- sendEncodings: [{
- dtx: 'enabled',
- active: false,
- ptime: 5,
- maxBitrate: 8,
- maxFramerate: 25,
- rid: 'foo'
- }]
- });
- }, `addTransceiver() with valid sendEncodings should succeed`);
-
- /*
- TODO
- 5.1. addTransceiver
- - Adding a transceiver will cause future calls to createOffer to add a media
- description for the corresponding transceiver, as defined in [JSEP]
- (section 5.2.2.).
-
- - Setting a new RTCSessionDescription may change mid to a non-null value,
- as defined in [JSEP] (section 5.5. and section 5.6.).
-
- 1. If the dictionary argument is present, and it has a streams member, let
- streams be that list of MediaStream objects.
-
- 5.2. RTCRtpSender Interface
- Create an RTCRtpSender
- 3. Let sender have an [[associated MediaStreams]] internal slot, representing
- a list of MediaStream objects that the MediaStreamTrack object of this
- sender is associated with.
-
- 4. Set sender's [[associated MediaStreams]] slot to streams.
-
- 5. Let sender have a [[send encodings]] internal slot, representing a list
- of RTCRtpEncodingParameters dictionaries.
-
- 6. If sendEncodings is given as input to this algorithm, and is non-empty,
- set the [[send encodings]] slot to sendEncodings. Otherwise, set it to a
- list containing a single RTCRtpEncodingParameters with active set to true.
-
- 5.3. RTCRtpReceiver Interface
- Create an RTCRtpReceiver
- 4. If an id string, id, was given as input to this algorithm, initialize
- track.id to id. (Otherwise the value generated when track was created
- will be used.)
-
- Tested in RTCPeerConnection-onnegotiationneeded.html
- 5.1. addTransceiver
- 12. Update the negotiation-needed flag for connection.
-
- Out of Scope
- 5.1. addTransceiver
- 8. If sendEncodings is set, then subsequent calls to createOffer will be
- configured to send multiple RTP encodings as defined in [JSEP]
- (section 5.2.2. and section 5.2.1.).
-
- When setRemoteDescription is called with a corresponding remote
- description that is able to receive multiple RTP encodings as defined
- in [JSEP] (section 3.7.), the RTCRtpSender may send multiple RTP
- encodings and the parameters retrieved via the transceiver's
- sender.getParameters() will reflect the encodings negotiated.
-
- 9. This specification does not define how to configure createOffer to
- receive multiple RTP encodings. However when setRemoteDescription is
- called with a corresponding remote description that is able to send
- multiple RTP encodings as defined in [JSEP], the RTCRtpReceiver may
- receive multiple RTP encodings and the parameters retrieved via the
- transceiver's receiver.getParameters() will reflect the encodings
- negotiated.
-
- Coverage Report
- Tested Not-Tested Non-Testable Total
- addTransceiver 14 1 3 18
- Create Sender 3 4 0 7
- Create Receiver 8 1 0 9
- Create Transceiver 7 0 0 7
-
- Total 32 6 3 41
- */
-</script>
+++ /dev/null
-<!doctype html>
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection canTrickleIceCandidates tests</title>
-</head>
-<body>
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script type="text/javascript">
- // tests support for RTCPeerConnection.canTrickleIceCandidates:
- // http://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-cantrickleicecandidates
- const sdp = 'v=0\r\n' +
- 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
- 's=-\r\n' +
- 't=0 0\r\n' +
- 'a=ice-options:trickle\r\n' +
- 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
- 'c=IN IP4 0.0.0.0\r\n' +
- 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
- 'a=ice-ufrag:someufrag\r\n' +
- 'a=ice-pwd:somelongpwdwithenoughrandomness\r\n' +
- '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\r\n' +
- 'a=setup:actpass\r\n' +
- 'a=rtcp-mux\r\n' +
- 'a=mid:mid1\r\n' +
- 'a=sendonly\r\n' +
- 'a=msid:stream1 track1\r\n' +
- 'a=ssrc:1001 cname:some\r\n' +
- 'a=rtpmap:111 opus/48000/2\r\n';
-
- test(function() {
- var pc = new RTCPeerConnection();
- assert_equals(pc.canTrickleIceCandidates, null, 'canTrickleIceCandidates property is null');
- }, 'canTrickleIceCandidates property is null prior to setRemoteDescription');
-
- promise_test(function(t) {
- var pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp}))
- .then(function() {
- assert_true(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is true after setRemoteDescription');
- })
- }, 'canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle');
-
- promise_test(function(t) {
- var pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.replace('a=ice-options:trickle\r\n', '')}))
- .then(function() {
- assert_false(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is false after setRemoteDescription');
- })
- }, 'canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle');
-</script>
-
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- let resolveIceCandidatePromise = null;
- const iceCandidatePromise = new Promise(r => resolveIceCandidatePromise = r);
- pc.onicecandidate = e => {
- resolveIceCandidatePromise(pc.localDescription.sdp);
- pc.onicecandidate = null;
- }
- pc.addTransceiver("audio");
- await pc.setLocalDescription(await pc.createOffer());
- assert_false(pc.localDescription.sdp.includes("a=candidate:"),
- "localDescription is missing candidate before onicecandidate");
- // The localDescription at the time of the onicecandidate event.
- const localDescriptionSdp = await iceCandidatePromise;
- assert_true(localDescriptionSdp.includes("a=candidate:"),
- "localDescription contains candidate after onicecandidate");
-}, 'localDescription contains candidates');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.connectionState</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.htm
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // exchangeIceCandidates
- // exchangeOfferAnswer
-
- /*
- 4.3.2. Interface Definition
- interface RTCPeerConnection : EventTarget {
- ...
- readonly attribute RTCPeerConnectionState connectionState;
- attribute EventHandler onconnectionstatechange;
- };
-
- 4.4.3. RTCPeerConnectionState Enum
- enum RTCPeerConnectionState {
- "new",
- "connecting",
- "connected",
- "disconnected",
- "failed",
- "closed"
- };
-
- 5.5. RTCDtlsTransport Interface
- interface RTCDtlsTransport {
- readonly attribute RTCIceTransport iceTransport;
- readonly attribute RTCDtlsTransportState state;
- ...
- };
-
- enum RTCDtlsTransportState {
- "new",
- "connecting",
- "connected",
- "closed",
- "failed"
- };
-
- 5.6. RTCIceTransport Interface
- interface RTCIceTransport {
- readonly attribute RTCIceTransportState state;
- ...
- };
-
- enum RTCIceTransportState {
- "new",
- "checking",
- "connected",
- "completed",
- "failed",
- "disconnected",
- "closed"
- };
- */
-
- /*
- 4.4.3. RTCPeerConnectionState Enum
- new
- Any of the RTCIceTransports or RTCDtlsTransports are in the new
- state and none of the transports are in the connecting, checking,
- failed or disconnected state, or all transports are in the closed state.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- assert_equals(pc.connectionState, 'new');
- }, 'Initial connectionState should be new');
-
- test(t => {
- const pc = new RTCPeerConnection();
- pc.close();
- assert_equals(pc.connectionState, 'closed');
- }, 'Closing the connection should set connectionState to closed');
-
- /*
- 4.4.3. RTCPeerConnectionState Enum
- connected
- All RTCIceTransports and RTCDtlsTransports are in the connected,
- completed or closed state and at least of them is in the connected
- or completed state.
-
- 5.5. RTCDtlsTransportState
- connected
- DTLS has completed negotiation of a secure connection.
-
- 5.6. RTCIceTransportState
- connected
- The RTCIceTransport has found a usable connection, but is still
- checking other candidate pairs to see if there is a better connection.
- It may also still be gathering and/or waiting for additional remote
- candidates. If consent checks [RFC7675] fail on the connection in use,
- and there are no other successful candidate pairs available, then the
- state transitions to "checking" (if there are candidate pairs remaining
- to be checked) or "disconnected" (if there are no candidate pairs to
- check, but the peer is still gathering and/or waiting for additional
- remote candidates).
-
- completed
- The RTCIceTransport has finished gathering, received an indication that
- there are no more remote candidates, finished checking all candidate
- pairs and found a connection. If consent checks [RFC7675] subsequently
- fail on all successful candidate pairs, the state transitions to "failed".
- */
-
- async_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- let had_connecting = false;
-
- const onConnectionStateChange = t.step_func(() => {
- const {connectionState} = pc1;
- if (connectionState === 'connecting') {
- had_connecting = true;
- } else if (connectionState === 'connected') {
- assert_true(had_connecting, "state should pass connecting before reaching connected");
- t.done();
- }
- });
-
- pc1.createDataChannel('test');
-
- pc1.addEventListener('connectionstatechange', onConnectionStateChange);
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- }, 'connection with one data channel should eventually have connected connection state');
-
- async_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const onConnectionStateChange = t.step_func(() => {
- const {connectionState} = pc1;
- if (connectionState === 'connected') {
- const sctpTransport = pc1.sctp;
-
- const dtlsTransport = sctpTransport.transport;
- assert_equals(dtlsTransport.state, 'connected',
- 'Expect DTLS transport to be in connected state');
-
- const iceTransport = dtlsTransport.iceTransport
- assert_true(iceTransport.state === 'connected' ||
- iceTransport.state === 'completed',
- 'Expect ICE transport to be in connected or completed state');
-
- t.done();
- }
- });
-
- pc1.createDataChannel('test');
-
- pc1.addEventListener('connectionstatechange', onConnectionStateChange);
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- }, 'connection with one data channel should eventually have transports in connected state');
-
- /*
- TODO
- 4.4.3. RTCPeerConnectionState Enum
- connecting
- Any of the RTCIceTransports or RTCDtlsTransports are in the
- connecting or checking state and none of them is in the failed state.
-
- disconnected
- Any of the RTCIceTransports or RTCDtlsTransports are in the disconnected
- state and none of them are in the failed or connecting or checking state.
-
- failed
- Any of the RTCIceTransports or RTCDtlsTransports are in a failed state.
-
- closed
- The RTCPeerConnection object's [[isClosed]] slot is true.
-
- 5.5. RTCDtlsTransportState
- new
- DTLS has not started negotiating yet.
-
- connecting
- DTLS is in the process of negotiating a secure connection.
-
- closed
- The transport has been closed.
-
- failed
- The transport has failed as the result of an error (such as a failure
- to validate the remote fingerprint).
-
- 5.6. RTCIceTransportState
- new
- The RTCIceTransport is gathering candidates and/or waiting for
- remote candidates to be supplied, and has not yet started checking.
-
- checking
- The RTCIceTransport has received at least one remote candidate and
- is checking candidate pairs and has either not yet found a connection
- or consent checks [RFC7675] have failed on all previously successful
- candidate pairs. In addition to checking, it may also still be gathering.
-
- failed
- The RTCIceTransport has finished gathering, received an indication that
- there are no more remote candidates, finished checking all candidate pairs,
- and all pairs have either failed connectivity checks or have lost consent.
-
- disconnected
- The ICE Agent has determined that connectivity is currently lost for this
- RTCIceTransport . This is more aggressive than failed, and may trigger
- intermittently (and resolve itself without action) on a flaky network.
- The way this state is determined is implementation dependent.
-
- Examples include:
- Losing the network interface for the connection in use.
- Repeatedly failing to receive a response to STUN requests.
-
- Alternatively, the RTCIceTransport has finished checking all existing
- candidates pairs and failed to find a connection (or consent checks
- [RFC7675] once successful, have now failed), but it is still gathering
- and/or waiting for additional remote candidates.
-
- closed
- The RTCIceTransport has shut down and is no longer responding to STUN requests.
- */
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- caller.addTrack(track, stream);
-
- await exchangeOfferAnswer(caller, callee);
-
- assert_equals(caller.iceConnectionState, 'new');
- assert_equals(callee.iceConnectionState, 'new');
- }, 'connectionState remains new when not adding remote ice candidates');
-
- promise_test(async t => {
-
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- caller.addTrack(track, stream);
-
- const states = [];
- caller.addEventListener('connectionstatechange', () => states.push(caller.connectionState));
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
-
- await listenToConnected(caller);
-
- assert_array_equals(states, ['connecting', 'connected']);
- }, 'connectionState transitions to connected via connecting');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
-
- stream.getTracks().forEach(track => pc1.addTrack(track, stream));
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await listenToIceConnected(pc2);
-
- pc2.onconnectionstatechange = t.unreached_func();
- pc2.close();
- assert_equals(pc2.connectionState, 'closed');
- await new Promise(r => t.step_timeout(r, 100));
- }, 'Closing a PeerConnection should not fire connectionstatechange event');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection constructor</title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script>
-test(function() {
- assert_equals(RTCPeerConnection.length, 0);
-}, 'RTCPeerConnection.length');
-
-// These are used for string and number dictionary members to see if they are
-// being accessed at all.
-const toStringThrows = { toString: function() { throw new Error; } };
-const toNumberThrows = Symbol();
-
-// Test the first argument of the constructor. The key is the argument itself,
-// and the value is the first argument for assert_throws_js, or false if no
-// exception should be thrown.
-const testArgs = {
- // No argument or equivalent.
- '': false,
- 'null': false,
- 'undefined': false,
- '{}': false,
-
- // certificates
- '{ certificates: null }': TypeError,
- '{ certificates: undefined }': false,
- '{ certificates: [] }': false,
- '{ certificates: [null] }': TypeError,
- '{ certificates: [undefined] }': TypeError,
-
- // iceCandidatePoolSize
- '{ iceCandidatePoolSize: toNumberThrows }': TypeError,
-}
-
-for (const arg in testArgs) {
- const expr = 'new RTCPeerConnection(' + arg + ')';
- test(function() {
- const throws = testArgs[arg];
- if (throws) {
- assert_throws_js(throws, function() {
- eval(expr);
- });
- } else {
- eval(expr);
- }
- }, expr);
-}
-
-// The initial values of attributes of RTCPeerConnection.
-const initialState = {
- 'localDescription': null,
- 'currentLocalDescription': null,
- 'pendingLocalDescription': null,
- 'remoteDescription': null,
- 'currentRemoteDescription': null,
- 'pendingRemoteDescription': null,
- 'signalingState': 'stable',
- 'iceGatheringState': 'new',
- 'iceConnectionState': 'new',
- 'connectionState': 'new',
- 'canTrickleIceCandidates': null,
- // TODO: defaultIceServers
-};
-
-for (const attr in initialState) {
- test(function() {
- // Use one RTCPeerConnection instance for all initial value tests.
- if (!window.pc) {
- window.pc = new RTCPeerConnection;
- }
- assert_equals(window.pc[attr], initialState[attr]);
- }, attr + ' initial value');
-}
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.createAnswer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- await promise_rejects_dom(t, 'InvalidStateError', pc.createAnswer());
-}, 'createAnswer() with null remoteDescription should reject with InvalidStateError');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- // generateDataChannelOffer() is defined in RTCPeerConnection-helper.js.
- const offer = await generateDataChannelOffer(pc);
- await pc.setRemoteDescription(offer);
- pc.close();
- await promise_rejects_dom(t, 'InvalidStateError', pc.createAnswer());
-}, 'createAnswer() when connection is closed should reject with InvalidStateError');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.createDataChannel</title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-const stopTracks = (...streams) => {
- streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
-};
-
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-/*
- 6.1. RTCPeerConnection Interface Extensions
-
- partial interface RTCPeerConnection {
- [...]
- RTCDataChannel createDataChannel(USVString label,
- optional RTCDataChannelInit dataChannelDict);
- [...]
- };
-
- 6.2. RTCDataChannel
-
- interface RTCDataChannel : EventTarget {
- readonly attribute USVString label;
- readonly attribute boolean ordered;
- readonly attribute unsigned short? maxPacketLifeTime;
- readonly attribute unsigned short? maxRetransmits;
- readonly attribute USVString protocol;
- readonly attribute boolean negotiated;
- readonly attribute unsigned short? id;
- readonly attribute RTCDataChannelState readyState;
- readonly attribute unsigned long bufferedAmount;
- attribute unsigned long bufferedAmountLowThreshold;
- [...]
- attribute DOMString binaryType;
- [...]
- };
-
- dictionary RTCDataChannelInit {
- boolean ordered = true;
- unsigned short maxPacketLifeTime;
- unsigned short maxRetransmits;
- USVString protocol = "";
- boolean negotiated = false;
- [EnforceRange]
- unsigned short id;
- };
- */
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.createDataChannel.length, 1);
- assert_throws_js(TypeError, () => pc.createDataChannel());
-}, 'createDataChannel with no argument should throw TypeError');
-
-/*
- 6.2. createDataChannel
- 2. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
- */
-test(t => {
- const pc = new RTCPeerConnection();
- pc.close();
- assert_equals(pc.signalingState, 'closed', 'signaling state');
- assert_throws_dom('InvalidStateError', () => pc.createDataChannel(''));
-}, 'createDataChannel with closed connection should throw InvalidStateError');
-
-/*
- 6.1. createDataChannel
- 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
- first argument.
- 6. Let options be the second argument.
- 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
- option's maxPacketLifeTime member, if present, otherwise null.
- 8. Let channel have a [[ReadyState]] internal slot initialized to "connecting".
- 9. Let channel have a [[BufferedAmount]] internal slot initialized to 0.
- 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
- option's maxRetransmits member, if present, otherwise null.
- 11. Let channel have an [[Ordered]] internal slot initialized to option's
- ordered member.
- 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
- protocol member.
- 14. Let channel have a [[Negotiated]] internal slot initialized to option's negotiated
- member.
- 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id
- member, if it is present and [[Negotiated]] is true, otherwise null.
- 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
- createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
- transport has already been negotiated, then initialize [[DataChannelId]] to a value
- generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
- to the next step. If no available ID could be generated, or if the value of the
- [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
- OperationError exception.
-
- Note
- If the [[DataChannelId]] slot is null after this step, it will be populated once
- the DTLS role is determined during the process of setting an RTCSessionDescription.
- 22. If channel is the first RTCDataChannel created on connection, update the
- negotiation-needed flag for connection.
-
-
- 6.2. RTCDataChannel
-
- A RTCDataChannel, created with createDataChannel or dispatched via a
- RTCDataChannelEvent, MUST initially be in the connecting state
-
- bufferedAmountLowThreshold
- [...] The bufferedAmountLowThreshold is initially zero on each new RTCDataChannel,
- but the application may change its value at any time.
-
- binaryType
- [...] When a RTCDataChannel object is created, the binaryType attribute MUST
- be initialized to the string "blob".
-
- 6.2. createDataChannel
- 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
- first argument.
-
- [ECMA262] 7.1.12. ToString(argument)
- undefined -> "undefined"
- null -> "null"
-
- [WebIDL] 3.10.15. Convert a DOMString to a sequence of Unicode scalar values
- */
-const labels = [
- ['"foo"', 'foo', 'foo'],
- ['null', null, 'null'],
- ['undefined', undefined, 'undefined'],
- ['lone surrogate', '\uD800', '\uFFFD'],
-];
-for (const [description, label, expected] of labels) {
- test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel(label);
- assert_equals(dc.label, expected);
- }, `createDataChannel with label ${description} should succeed`);
-}
-
-/*
- 6.2. RTCDataChannel
- createDataChannel
- 11. Let channel have an [[Ordered]] internal slot initialized to option's
- ordered member.
- */
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', { ordered: false });
- assert_equals(dc.ordered, false);
-}, 'createDataChannel with ordered false should succeed');
-
-// true as the default value of a boolean is confusing because null is converted
-// to false while undefined is converted to true.
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const dc1 = pc.createDataChannel('', { ordered: null });
- assert_equals(dc1.ordered, false);
- const dc2 = pc.createDataChannel('', { ordered: undefined });
- assert_equals(dc2.ordered, true);
-}, 'createDataChannel with ordered null/undefined should succeed');
-
-/*
- 6.2. RTCDataChannel
- createDataChannel
- 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
- option's maxPacketLifeTime member, if present, otherwise null.
- */
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', { maxPacketLifeTime: 0 });
- assert_equals(dc.maxPacketLifeTime, 0);
-}, 'createDataChannel with maxPacketLifeTime 0 should succeed');
-
-/*
- 6.2. RTCDataChannel
- createDataChannel
- 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
- option's maxRetransmits member, if present, otherwise null.
- */
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', { maxRetransmits: 0 });
- assert_equals(dc.maxRetransmits, 0);
-}, 'createDataChannel with maxRetransmits 0 should succeed');
-
-/*
- 6.2. createDataChannel
- 18. If both [[MaxPacketLifeTime]] and [[MaxRetransmits]] attributes are set (not null),
- throw a TypeError.
- */
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- pc.createDataChannel('', {
- maxPacketLifeTime: undefined,
- maxRetransmits: undefined
- });
-}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits undefined should succeed');
-
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.createDataChannel('', {
- maxPacketLifeTime: 0,
- maxRetransmits: 0
- }));
- assert_throws_js(TypeError, () => pc.createDataChannel('', {
- maxPacketLifeTime: 42,
- maxRetransmits: 42
- }));
-}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError');
-
-/*
- 6.2. RTCDataChannel
- createDataChannel
- 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
- protocol member.
- */
-const protocols = [
- ['"foo"', 'foo', 'foo'],
- ['null', null, 'null'],
- ['undefined', undefined, ''],
- ['lone surrogate', '\uD800', '\uFFFD'],
-];
-for (const [description, protocol, expected] of protocols) {
- test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', { protocol });
- assert_equals(dc.protocol, expected);
- }, `createDataChannel with protocol ${description} should succeed`);
-}
-
-/*
- 6.2. RTCDataChannel
- createDataChannel
- 20. If [[DataChannelId]] is equal to 65535, which is greater than the maximum allowed
- ID of 65534 but still qualifies as an unsigned short, throw a TypeError.
- */
-for (const id of [0, 1, 65534]) {
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const dc = pc.createDataChannel('', { id });
- assert_equals(dc.id, null);
- }, `createDataChannel with id ${id} and negotiated not set should succeed, but not set the channel's id`);
-}
-
-for (const id of [0, 1]) {
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', { 'negotiated': true, 'id': id });
- assert_equals(dc.id, id);
- }, `createDataChannel with id ${id} and negotiated true should succeed, and set the channel's id`);
-}
-
-for (const id of [-1, 65535, 65536]) {
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- assert_throws_js(TypeError, () => pc.createDataChannel('', { id }));
- }, `createDataChannel with id ${id} and negotiated not set should throw TypeError`);
-}
-
-for (const id of [-1, 65535, 65536]) {
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.createDataChannel('',
- { 'negotiated': true, 'id': id }));
- }, `createDataChannel with id ${id} should throw TypeError`);
-}
-
-/*
- 6.2. createDataChannel
- 5. If [[DataChannelLabel]] is longer than 65535 bytes, throw a TypeError.
- */
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('l'.repeat(65536)));
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('l'.repeat(65536), {
- negotiated: true,
- id: 42
- }));
-}, 'createDataChannel with too long label should throw TypeError');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('\u00b5'.repeat(32768)));
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('\u00b5'.repeat(32768), {
- negotiated: true,
- id: 42
- }));
-}, 'createDataChannel with too long label (2 byte unicode) should throw TypeError');
-
-/*
- 6.2. label
- [...] Scripts are allowed to create multiple RTCDataChannel objects with the same label.
- [...]
- */
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const label = 'test';
-
- pc.createDataChannel(label);
- pc.createDataChannel(label);
-}, 'createDataChannel with same label used twice should not throw');
-
-/*
- 6.2. createDataChannel
- 13. If [[DataChannelProtocol]] is longer than 65535 bytes long, throw a TypeError.
- */
-
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
- const channel = pc.createDataChannel('', { negotiated: true, id: 42 });
- assert_equals(channel.negotiated, true);
-}, 'createDataChannel with negotiated true and id should succeed');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('', {
- protocol: 'p'.repeat(65536)
- }));
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('', {
- protocol: 'p'.repeat(65536),
- negotiated: true,
- id: 42
- }));
-}, 'createDataChannel with too long protocol should throw TypeError');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('', {
- protocol: '\u00b6'.repeat(32768)
- }));
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('', {
- protocol: '\u00b6'.repeat(32768),
- negotiated: true,
- id: 42
- }));
-}, 'createDataChannel with too long protocol (2 byte unicode) should throw TypeError');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const label = 'l'.repeat(65535);
- const protocol = 'p'.repeat(65535);
-
- const dc = pc.createDataChannel(label, {
- protocol: protocol
- });
-
- assert_equals(dc.label, label);
- assert_equals(dc.protocol, protocol);
-}, 'createDataChannel with maximum length label and protocol should succeed');
-
-/*
- 6.2 createDataChannel
- 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id member,
- if it is present and [[Negotiated]] is true, otherwise null.
-
- NOTE
- This means the id member will be ignored if the data channel is negotiated in-band; this
- is intentional. Data channels negotiated in-band should have IDs selected based on the
- DTLS role, as specified in [RTCWEB-DATA-PROTOCOL].
- */
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', {
- negotiated: false,
- });
- assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
-}, 'createDataChannel with negotiated false should succeed');
-
-test(t => {
- const pc = new RTCPeerConnection;
- t.add_cleanup(() => pc.close());
-
- const dc = pc.createDataChannel('', {
- negotiated: false,
- id: 42
- });
- assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
- assert_equals(dc.id, null, 'Expect dc.id to be ignored (null)');
-}, 'createDataChannel with negotiated false and id 42 should ignore the id');
-
-/*
- 6.2. createDataChannel
- 16. If [[Negotiated]] is true and [[DataChannelId]] is null, throw a TypeError.
- */
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () =>
- pc.createDataChannel('test', {
- negotiated: true
- }));
-}, 'createDataChannel with negotiated true and id not defined should throw TypeError');
-
-/*
- 4.4.1.6. Set the RTCSessionSessionDescription
- 2.2.6. If description is of type "answer" or "pranswer", then run the
- following steps:
- 3. If description negotiates the DTLS role of the SCTP transport, and there is an
- RTCDataChannel with a null id, then generate an ID according to
- [RTCWEB-DATA-PROTOCOL]. [...]
-
- 6.1. createDataChannel
- 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
- createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
- transport has already been negotiated, then initialize [[DataChannelId]] to a value
- generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
- to the next step. If no available ID could be generated, or if the value of the
- [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
- OperationError exception.
-
- Note
- If the [[DataChannelId]] slot is null after this step, it will be populated once
- the DTLS role is determined during the process of setting an RTCSessionDescription.
- */
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const negotiatedDc = pc1.createDataChannel('negotiated-channel', {
- negotiated: true,
- id: 42,
- });
- assert_equals(negotiatedDc.id, 42, 'Expect negotiatedDc.id to be 42');
-
- const dc1 = pc1.createDataChannel('channel');
- assert_equals(dc1.id, null, 'Expect initial id to be null');
-
- const offer = await pc1.createOffer();
- await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
-
- assert_not_equals(dc1.id, null,
- 'Expect dc1.id to be assigned after remote description has been set');
-
- assert_greater_than_equal(dc1.id, 0,
- 'Expect dc1.id to be set to valid unsigned short');
-
- assert_less_than(dc1.id, 65535,
- 'Expect dc1.id to be set to valid unsigned short');
-
- const dc2 = pc1.createDataChannel('channel');
-
- assert_not_equals(dc2.id, null,
- 'Expect dc2.id to be assigned after remote description has been set');
-
- assert_greater_than_equal(dc2.id, 0,
- 'Expect dc2.id to be set to valid unsigned short');
-
- assert_less_than(dc2.id, 65535,
- 'Expect dc2.id to be set to valid unsigned short');
-
- assert_not_equals(dc2, dc1,
- 'Expect channels created from same label to be different');
-
- assert_equals(dc2.label, dc1.label,
- 'Expect different channels can have the same label but different id');
-
- assert_not_equals(dc2.id, dc1.id,
- 'Expect different channels can have the same label but different id');
-
- assert_equals(negotiatedDc.id, 42,
- 'Expect negotiatedDc.id to be 42 after remote description has been set');
-}, 'Channels created (after setRemoteDescription) should have id assigned');
-
-test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const dc1 = pc.createDataChannel('channel-1', {
- negotiated: true,
- id: 42,
- });
- assert_equals(dc1.id, 42,
- 'Expect dc1.id to be 42');
-
- const dc2 = pc.createDataChannel('channel-2', {
- negotiated: true,
- id: 43,
- });
- assert_equals(dc2.id, 43,
- 'Expect dc2.id to be 43');
-
- assert_throws_dom('OperationError', () =>
- pc.createDataChannel('channel-3', {
- negotiated: true,
- id: 42,
- }));
-
-}, 'Reusing a data channel id that is in use should throw OperationError');
-
-// We've seen implementations behaving differently before and after the connection has been
-// established.
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel('channel-1', {
- negotiated: true,
- id: 42,
- });
- assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
-
- const dc2 = pc1.createDataChannel('channel-2', {
- negotiated: true,
- id: 43,
- });
- assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
-
- const offer = await pc1.createOffer();
- await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
-
- assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
-
- assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
-
- assert_throws_dom('OperationError', () =>
- pc1.createDataChannel('channel-3', {
- negotiated: true,
- id: 42,
- }));
-}, 'Reusing a data channel id that is in use (after setRemoteDescription) should throw ' +
- 'OperationError');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel('channel-1');
-
- const offer = await pc1.createOffer();
- await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
-
- assert_not_equals(dc1.id, null,
- 'Expect dc1.id to be assigned after remote description has been set');
-
- assert_throws_dom('OperationError', () =>
- pc1.createDataChannel('channel-2', {
- negotiated: true,
- id: dc1.id,
- }));
-}, 'Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) ' +
- 'should throw OperationError');
-
-
-for (const options of [{}, {negotiated: true, id: 0}]) {
- const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
-
- // Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- await createDataChannelPair(t, options, pc1);
-
- const dc = pc1.createDataChannel('');
- assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state');
- }, `New ${mode} should be in the connecting state after creation ` +
- `(after connection establishment)`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
- pc1.addTrack(audio, stream);
- pc1.addTrack(video, stream);
- await createDataChannelPair(t, options, pc1);
- }, `addTrack, then creating ${mode}, should negotiate properly`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"});
- t.add_cleanup(() => pc1.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
- pc1.addTrack(audio, stream);
- pc1.addTrack(video, stream);
- await createDataChannelPair(t, options, pc1);
- }, `addTrack, then creating ${mode}, should negotiate properly when max-bundle is used`);
-
-/*
-This test is disabled until https://github.com/w3c/webrtc-pc/issues/2562
-has been resolved; it presupposes that stopping the first transceiver
-breaks the transport.
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"});
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
- pc1.addTrack(audio, stream);
- pc1.addTrack(video, stream);
- const [dc1, dc2] = await createDataChannelPair(t, options, pc1, pc2);
-
- pc2.getTransceivers()[0].stop();
- const dc1Closed = new Promise(r => dc1.onclose = r);
- await exchangeOfferAnswer(pc1, pc2);
- await dc1Closed;
- }, `Stopping the bundle-tag when there is a ${mode} in the bundle ` +
- `should kill the DataChannel`);
-*/
-}
-
-/*
- Untestable
- 6.1. createDataChannel
- 19. If a setting, either [[MaxPacketLifeTime]] or [[MaxRetransmits]], has been set to
- indicate unreliable mode, and that value exceeds the maximum value supported
- by the user agent, the value MUST be set to the user agents maximum value.
-
- 23. Return channel and continue the following steps in parallel.
- 24. Create channel's associated underlying data transport and configure
- it according to the relevant properties of channel.
-
- Tested in RTCPeerConnection-onnegotiationneeded.html
- 22. If channel is the first RTCDataChannel created on connection, update the
- negotiation-needed flag for connection.
-
- Tested in RTCDataChannel-id.html
- - Odd/even rules for '.id'
-
- Tested in RTCDataChannel-dcep.html
- - Transmission of '.label' and further options
-*/
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.createOffer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // countAudioLine()
- // countVideoLine()
- // assert_session_desc_similar()
-
- /*
- * 4.3.2. createOffer()
- */
-
- /*
- * Final steps to create an offer
- * 4. Let offer be a newly created RTCSessionDescriptionInit dictionary
- * with its type member initialized to the string "offer" and its sdp member
- * initialized to sdpString.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.pendingLocalDescription, offer);
- assert_equals(pc.currentLocalDescription, null);
-
- assert_array_equals(states, ['have-local-offer']);
- }));
- }, 'createOffer() and then setLocalDescription() should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.close();
-
- return promise_rejects_dom(t, 'InvalidStateError',
- pc.createOffer());
- }, 'createOffer() after connection is closed should reject with InvalidStateError');
-
- /*
- * Final steps to create an offer
- * 2. If connection was modified in such a way that additional inspection of the
- * system state is necessary, then in parallel begin the steps to create an
- * offer again, given p, and abort these steps.
- *
- * This test might hit step 2 of final steps to create an offer. But the media stream
- * is likely added already by the time steps to create an offer is executed, because
- * that is enqueued as an operation.
- * Either way it verifies that the media stream is included in the offer even though
- * the stream is added after synchronous call to createOffer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('audio');
- const promise = pc.createOffer();
-
- //pc.addTransceiver('audio');
- return promise.then(offer => {
- assert_equals(countAudioLine(offer.sdp), 1,
- 'Expect m=audio line to be found in offer SDP')
- });
- }, 'When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream');
-
- /*
- * TODO
- * 4.3.2 createOffer
- * 3. If connection is configured with an identity provider, and an identity
- * assertion has not yet been generated using said identity provider, then
- * begin the identity assertion request process if it has not already begun.
- * Steps to create an offer
- * 1. If the need for an identity assertion was identified when createOffer was
- * invoked, wait for the identity assertion request process to complete.
- *
- * Non-Testable
- * 4.3.2 createOffer
- * Steps to create an offer
- * 4. Inspect the system state to determine the currently available resources as
- * necessary for generating the offer, as described in [JSEP] (section 4.1.6.).
- * 5. If this inspection failed for any reason, reject p with a newly created
- * OperationError and abort these steps.
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const offer = await pc.createOffer();
-
- assert_equals(pc.pendingLocalDescription, null,
- 'pendingLocalDescription is null before setLocalDescription');
- const promise = pc.setLocalDescription(offer);
- assert_equals(pc.pendingLocalDescription, null,
- 'pendingLocalDescription is still null while promise pending');
- await promise;
- assert_not_equals(pc.pendingLocalDescription, null,
- 'pendingLocalDescription is not null after await');
-}, "pendingLocalDescription is surfaced at the right time");
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const offer = await pc.createOffer();
-
- assert_equals(pc.pendingRemoteDescription, null,
- 'pendingRemoteDescription is null before setRemoteDescription');
- const promise = pc.setRemoteDescription(offer);
- assert_equals(pc.pendingRemoteDescription, null,
- 'pendingRemoteDescription is still null while promise pending');
- await promise;
- assert_not_equals(pc.pendingRemoteDescription, null,
- 'pendingRemoteDescription is not null after await');
-}, "pendingRemoteDescription is surfaced at the right time");
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
-
- assert_equals(pc2.currentLocalDescription, null,
- 'currentLocalDescription is null before setLocalDescription');
- const promise = pc2.setLocalDescription(answer);
- assert_equals(pc2.currentLocalDescription, null,
- 'currentLocalDescription is still null while promise pending');
- await promise;
- assert_not_equals(pc2.currentLocalDescription, null,
- 'currentLocalDescription is not null after await');
-}, "currentLocalDescription is surfaced at the right time");
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
-
- assert_equals(pc1.currentRemoteDescription, null,
- 'currentRemoteDescription is null before setRemoteDescription');
- const promise = pc1.setRemoteDescription(answer);
- assert_equals(pc1.currentRemoteDescription, null,
- 'currentRemoteDescription is still null while promise pending');
- await promise;
- assert_not_equals(pc1.currentRemoteDescription, null,
- 'currentRemoteDescription is not null after await');
-}, "currentRemoteDescription is surfaced at the right time");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.iceGatheringState</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await initialOfferAnswerWithIceGatheringStateTransitions(
- pc1, pc2);
- await pc1.setLocalDescription(await pc1.createOffer({iceRestart: true}));
- await iceGatheringStateTransitions(pc1, 'gathering', 'complete');
- expectNoMoreGatheringStateChanges(t, pc1);
- await pc1.setLocalDescription({type: 'rollback'});
- await new Promise(r => t.step_timeout(r, 1000));
-}, 'rolling back an ICE restart when gathering is complete should not result in iceGatheringState changes');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('audio', { direction: 'recvonly' });
- await pc.setLocalDescription(
- await pc.createOffer());
- await iceGatheringStateTransitions(pc, 'gathering', 'complete');
- await pc.setLocalDescription({type: 'rollback'});
- await iceGatheringStateTransitions(pc, 'new');
-}, 'setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "complete"');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('audio', { direction: 'recvonly' });
- await pc.setLocalDescription(
- await pc.createOffer());
- await iceGatheringStateTransitions(pc, 'gathering');
- await pc.setLocalDescription({type: 'rollback'});
- // We might go directly to 'new', or we might go to 'complete' first,
- // depending on timing. Allow either.
- const results = await Promise.allSettled([
- iceGatheringStateTransitions(pc, 'new'),
- iceGatheringStateTransitions(pc, 'complete', 'new')]);
- assert_true(results.some(result => result.status == 'fulfilled'),
- 'ICE gathering state should go back to "new", possibly through "complete"');
-}, 'setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "gathering"');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>Test RTCPeerConnection.generateCertificate</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
-
- /*
- * 4.10. Certificate Management
- * partial interface RTCPeerConnection {
- * static Promise<RTCCertificate> generateCertificate(
- * AlgorithmIdentifier keygenAlgorithm);
- * };
- *
- * 4.10.2. RTCCertificate Interface
- * interface RTCCertificate {
- * readonly attribute DOMTimeStamp expires;
- * ...
- * };
- *
- * [WebCrypto]
- * 11. Algorithm Dictionary
- * typedef (object or DOMString) AlgorithmIdentifier;
- */
-
- /*
- * 4.10. The following values must be supported by a user agent:
- * { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048,
- * publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
- * and { name: "ECDSA", namedCurve: "P-256" }.
- */
- promise_test(t =>
- RTCPeerConnection.generateCertificate({
- name: 'RSASSA-PKCS1-v1_5',
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: 'SHA-256'
- }).then(cert => {
- assert_true(cert instanceof RTCCertificate,
- 'Expect cert to be instance of RTCCertificate');
-
- assert_greater_than(cert.expires, Date.now(),
- 'Expect generated certificate to expire reasonably long after current time');
- }),
- 'generateCertificate() with compulsary RSASSA-PKCS1-v1_5 parameters should succeed');
-
- promise_test(t =>
- RTCPeerConnection.generateCertificate({
- name: 'ECDSA',
- namedCurve: 'P-256'
- }).then(cert => {
- assert_true(cert instanceof RTCCertificate,
- 'Expect cert to be instance of RTCCertificate');
-
- assert_greater_than(cert.expires, Date.now(),
- 'Expect generated certificate to expire reasonably long after current time');
- }),
- 'generateCertificate() with compulsary ECDSA parameters should succeed');
-
- /*
- * 4.10. A user agent must reject a call to generateCertificate() with a
- * DOMException of type NotSupportedError if the keygenAlgorithm
- * parameter identifies an algorithm that the user agent cannot or
- * will not use to generate a certificate for RTCPeerConnection.
- */
- promise_test(t =>
- promise_rejects_dom(t, 'NotSupportedError',
- RTCPeerConnection.generateCertificate('invalid-algo')),
- 'generateCertificate() with invalid string algorithm should reject with NotSupportedError');
-
- promise_test(t =>
- promise_rejects_dom(t, 'NotSupportedError',
- RTCPeerConnection.generateCertificate({
- name: 'invalid-algo'
- })),
- 'generateCertificate() with invalid algorithm dict should reject with NotSupportedError');
-
- /*
- * 4.10.1. Dictionary RTCCertificateExpiration
- * dictionary RTCCertificateExpiration {
- * [EnforceRange]
- * DOMTimeStamp expires;
- * };
- *
- * If this parameter is present it indicates the maximum time that
- * the RTCCertificate is valid for relative to the current time.
- *
- * When generateCertificate is called with an object argument,
- * the user agent attempts to convert the object into a
- * RTCCertificateExpiration. If this is unsuccessful, immediately
- * return a promise that is rejected with a newly created TypeError
- * and abort processing.
- */
-
- promise_test(t => {
- const start = Date.now();
- return RTCPeerConnection.generateCertificate({
- name: 'ECDSA',
- namedCurve: 'P-256',
- expires: 2000
- }).then(cert => {
- assert_approx_equals(cert.expires, start+2000, 1000);
- })
- }, 'generateCertificate() with valid expires parameter should succeed');
-
- promise_test(t => {
- return RTCPeerConnection.generateCertificate({
- name: 'ECDSA',
- namedCurve: 'P-256',
- expires: 0
- }).then(cert => {
- assert_less_than_equal(cert.expires, Date.now());
- })
- }, 'generateCertificate() with 0 expires parameter should generate expired cert');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.getStats</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCStats-helper.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // webrtc-pc 20171130
- // webrtc-stats 20171122
-
- // The following helper function is called from RTCPeerConnection-helper.js
- // getTrackFromUserMedia
-
- // The following helper function is called from RTCStats-helper.js
- // validateStatsReport
- // assert_stats_report_has_stats
-
- // The following helper function is called from RTCPeerConnection-helper.js
- // exchangeIceCandidates
- // exchangeOfferAnswer
-
- /*
- 8.2. getStats
- 1. Let selectorArg be the method's first argument.
- 2. Let connection be the RTCPeerConnection object on which the method was invoked.
- 3. If selectorArg is null, let selector be null.
- 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
- or RTCRtpReceiver on connection which track member matches selectorArg.
- If no such sender or receiver exists, or if more than one sender or
- receiver fit this criteria, return a promise rejected with a newly
- created InvalidAccessError.
- 5. Let p be a new promise.
- 6. Run the following steps in parallel:
- 1. Gather the stats indicated by selector according to the stats selection algorithm.
- 2. Resolve p with the resulting RTCStatsReport object, containing the gathered stats.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return pc.getStats();
- }, 'getStats() with no argument should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return pc.getStats(null);
- }, 'getStats(null) should succeed');
-
- /*
- 8.2. getStats
- 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
- or RTCRtpReceiver on connection which track member matches selectorArg.
- If no such sender or receiver exists, or if more than one sender or
- receiver fit this criteria, return a promise rejected with a newly
- created InvalidAccessError.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return getTrackFromUserMedia('audio')
- .then(([track, mediaStream]) => {
- return promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(track));
- });
- }, 'getStats() with track not added to connection should reject with InvalidAccessError');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return getTrackFromUserMedia('audio')
- .then(([track, mediaStream]) => {
- pc.addTrack(track, mediaStream);
- return pc.getStats(track);
- });
- }, 'getStats() with track added via addTrack should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- pc.addTransceiver(track);
-
- return pc.getStats(track);
- }, 'getStats() with track added via addTransceiver should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver1 = pc.addTransceiver('audio');
-
- // Create another transceiver that resends what
- // is being received, kind of like echo
- const transceiver2 = pc.addTransceiver(transceiver1.receiver.track);
- assert_equals(transceiver1.receiver.track, transceiver2.sender.track);
-
- return promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(transceiver1.receiver.track));
- }, 'getStats() with track associated with both sender and receiver should reject with InvalidAccessError');
-
- /*
- 8.5. The stats selection algorithm
- 2. If selector is null, gather stats for the whole connection, add them to result,
- return result, and abort these steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return pc.getStats()
- .then(statsReport => {
- validateStatsReport(statsReport);
- assert_stats_report_has_stats(statsReport, ['peer-connection']);
- });
- }, 'getStats() with no argument should return stats report containing peer-connection stats on an empty PC');
-
- promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTrack(track, mediaStream);
- exchangeIceCandidates(pc, pc2);
- await exchangeOfferAnswer(pc, pc2);
- await listenToConnected(pc);
- const statsReport = await pc.getStats();
- getRequiredStats(statsReport, 'peer-connection');
- getRequiredStats(statsReport, 'outbound-rtp');
- }, 'getStats() track with stream returns peer-connection and outbound-rtp stats');
-
- promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTrack(track);
- exchangeIceCandidates(pc, pc2);
- await exchangeOfferAnswer(pc, pc2);
- await listenToConnected(pc);
- const statsReport = await pc.getStats();
- getRequiredStats(statsReport, 'peer-connection');
- getRequiredStats(statsReport, 'outbound-rtp');
- }, 'getStats() track without stream returns peer-connection and outbound-rtp stats');
-
- promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTrack(track, mediaStream);
- exchangeIceCandidates(pc, pc2);
- await exchangeOfferAnswer(pc, pc2);
- await listenToConnected(pc);
- const statsReport = await pc.getStats();
- assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
- }, 'getStats() audio outbound-rtp contains all mandatory stats');
-
- /*
- 8.5. The stats selection algorithm
- 3. If selector is an RTCRtpSender, gather stats for and add the following objects
- to result:
- - All RTCOutboundRTPStreamStats objects corresponding to selector.
- - All stats objects referenced directly or indirectly by the RTCOutboundRTPStreamStats
- objects added.
- */
- promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
-
- let [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTrack(track, mediaStream);
- exchangeIceCandidates(pc, pc2);
- await exchangeOfferAnswer(pc, pc2);
- await listenToConnected(pc);
- const stats = await pc.getStats(track);
- getRequiredStats(stats, 'outbound-rtp');
- }, `getStats() on track associated with RTCRtpSender should return stats report containing outbound-rtp stats`);
-
- /*
- 8.5. The stats selection algorithm
- 4. If selector is an RTCRtpReceiver, gather stats for and add the following objects
- to result:
- - All RTCInboundRTPStreamStats objects corresponding to selector.
- - All stats objects referenced directly or indirectly by the RTCInboundRTPStreamStats
- added.
- */
- promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
-
- let [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTrack(track, mediaStream);
- exchangeIceCandidates(pc, pc2);
- await exchangeOfferAnswer(pc, pc2);
- // Wait for unmute if the track is not already unmuted.
- // According to spec, it should be muted when being created, but this
- // is not what this test is testing, so allow it to be unmuted.
- if (pc2.getReceivers()[0].track.muted) {
- await new Promise(resolve => {
- pc2.getReceivers()[0].track.addEventListener('unmute', resolve);
- });
- }
- const stats = await pc2.getStats(pc2.getReceivers()[0].track);
- getRequiredStats(stats, 'inbound-rtp');
- }, `getStats() on track associated with RTCRtpReceiver should return stats report containing inbound-rtp stats`);
-
- /*
- 8.6 Mandatory To Implement Stats
- An implementation MUST support generating statistics of the following types
- when the corresponding objects exist on a PeerConnection, with the attributes
- that are listed when they are valid for that object.
- */
-
- const mandatoryStats = [
- "codec",
- "inbound-rtp",
- "outbound-rtp",
- "remote-inbound-rtp",
- "remote-outbound-rtp",
- "media-source",
- "peer-connection",
- "data-channel",
- "sender",
- "receiver",
- "transport",
- "candidate-pair",
- "local-candidate",
- "remote-candidate",
- "certificate"
- ];
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc.addTransceiver(track);
- pc.addTransceiver(track);
- await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(track));
- }, `getStats(track) should not work if multiple senders have the same track`);
-
- promise_test(async t => {
- const kMinimumTimeElapsedBetweenGetStatsCallsMs = 500;
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const t0 = Math.floor(performance.now());
- const t0Stats = getRequiredStats(await pc.getStats(), 'peer-connection');
- await new Promise(
- r => t.step_timeout(r, kMinimumTimeElapsedBetweenGetStatsCallsMs));
- const t1Stats = getRequiredStats(await pc.getStats(), 'peer-connection');
- const t1 = Math.ceil(performance.now());
- const maximumTimeElapsedBetweenGetStatsCallsMs = t1 - t0;
- const deltaTimestampMs = t1Stats.timestamp - t0Stats.timestamp;
- // The delta must be at least the time we waited between calls.
- assert_greater_than_equal(deltaTimestampMs,
- kMinimumTimeElapsedBetweenGetStatsCallsMs);
- // The delta must be at most the time elapsed before the first getStats()
- // call and after the second getStats() call.
- assert_less_than_equal(deltaTimestampMs,
- maximumTimeElapsedBetweenGetStatsCallsMs);
- }, `RTCStats.timestamp increases with time passing`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.getTransceivers</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- /*
- * 5.1. RTCPeerConnection Interface Extensions
- * partial interface RTCPeerConnection {
- * sequence<RTCRtpSender> getSenders();
- * sequence<RTCRtpReceiver> getReceivers();
- * sequence<RTCRtpTransceiver> getTransceivers();
- * ...
- * };
- */
-
- test(t => {
- const pc = new RTCPeerConnection();
-
- assert_idl_attribute(pc, 'getSenders');
- const senders = pc.getSenders();
- assert_array_equals([], senders, 'Expect senders to be empty array');
-
- assert_idl_attribute(pc, 'getReceivers');
- const receivers = pc.getReceivers();
- assert_array_equals([], receivers, 'Expect receivers to be empty array');
-
- assert_idl_attribute(pc, 'getTransceivers');
- const transceivers = pc.getTransceivers();
- assert_array_equals([], transceivers, 'Expect transceivers to be empty array');
-
- }, 'Initial peer connection should have list of zero senders, receivers and transceivers');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection-helper tests</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const transceiver = pc1.addTransceiver('video');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- await waitForState(transceiver.sender.transport, 'connected');
-}, 'Setting up a connection using helpers and defaults should work');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.iceConnectionState - disconnection</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream = await getNoiseStream({audio:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- caller.addTrack(track, stream);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
-
- await listenToIceConnected(caller);
-
- callee.close();
- await waitForIceStateChange(caller, ['disconnected', 'failed']);
- // TODO: this should eventually transition to failed but that takes
- // somewhat long (15-30s) so is not testable.
- }, 'ICE goes to disconnected if the other side goes away');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.iceConnectionState</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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
-
- /*
- 4.3.2. Interface Definition
- interface RTCPeerConnection : EventTarget {
- ...
- readonly attribute RTCIceConnectionState iceConnectionState;
- attribute EventHandler oniceconnectionstatechange;
- };
-
- 4.4.4 RTCIceConnectionState Enum
- enum RTCIceConnectionState {
- "new",
- "checking",
- "connected",
- "completed",
- "failed",
- "disconnected",
- "closed"
- };
-
- 5.6. RTCIceTransport Interface
- interface RTCIceTransport {
- readonly attribute RTCIceTransportState state;
- attribute EventHandler onstatechange;
-
- ...
- };
-
- enum RTCIceTransportState {
- "new",
- "checking",
- "connected",
- "completed",
- "failed",
- "disconnected",
- "closed"
- };
- */
-
- /*
- 4.4.4 RTCIceConnectionState Enum
- new
- Any of the RTCIceTransports are in the new state and none of them
- are in the checking, failed or disconnected state, or all
- RTCIceTransport s are in the closed state.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- assert_equals(pc.iceConnectionState, 'new');
- }, 'Initial iceConnectionState should be new');
-
- test(t => {
- const pc = new RTCPeerConnection();
- pc.close();
- assert_equals(pc.iceConnectionState, 'closed');
- }, 'Closing the connection should set iceConnectionState to closed');
-
- /*
- 4.4.4 RTCIceConnectionState Enum
- checking
- Any of the RTCIceTransport s are in the checking state and none of
- them are in the failed or disconnected state.
-
- connected
- All RTCIceTransport s are in the connected, completed or closed state
- and at least one of them is in the connected state.
-
- completed
- All RTCIceTransport s are in the completed or closed state and at least
- one of them is in the completed state.
-
- checking
- The RTCIceTransport has received at least one remote candidate and
- is checking candidate pairs and has either not yet found a connection
- or consent checks [RFC7675] have failed on all previously successful
- candidate pairs. In addition to checking, it may also still be gathering.
-
- 5.6. enum RTCIceTransportState
- connected
- The RTCIceTransport has found a usable connection, but is still
- checking other candidate pairs to see if there is a better connection.
- It may also still be gathering and/or waiting for additional remote
- candidates. If consent checks [RFC7675] fail on the connection in use,
- and there are no other successful candidate pairs available, then the
- state transitions to "checking" (if there are candidate pairs remaining
- to be checked) or "disconnected" (if there are no candidate pairs to
- check, but the peer is still gathering and/or waiting for additional
- remote candidates).
-
- completed
- The RTCIceTransport has finished gathering, received an indication that
- there are no more remote candidates, finished checking all candidate
- pairs and found a connection. If consent checks [RFC7675] subsequently
- fail on all successful candidate pairs, the state transitions to "failed".
- */
- async_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- let had_checking = false;
-
- const onIceConnectionStateChange = t.step_func(() => {
- const {iceConnectionState} = pc1;
- if (iceConnectionState === 'checking') {
- had_checking = true;
- } else if (iceConnectionState === 'connected' ||
- iceConnectionState === 'completed') {
- assert_true(had_checking, 'state should pass checking before' +
- ' reaching connected or completed');
- t.done();
- } else if (iceConnectionState === 'failed') {
- assert_unreached("ICE should not fail");
- }
- });
-
- pc1.createDataChannel('test');
-
- pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- }, 'connection with one data channel should eventually have connected or ' +
- 'completed connection state');
-
-async_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- const onIceConnectionStateChange = t.step_func(() => {
- const { iceConnectionState } = pc1;
-
- if(iceConnectionState === 'checking') {
- const iceTransport = pc1.sctp.transport.iceTransport;
-
- assert_equals(iceTransport.state, 'checking',
- 'Expect ICE transport to be in checking state when' +
- ' iceConnectionState is checking');
-
- } else if(iceConnectionState === 'connected') {
- const iceTransport = pc1.sctp.transport.iceTransport;
-
- assert_equals(iceTransport.state, 'connected',
- 'Expect ICE transport to be in connected state when' +
- ' iceConnectionState is connected');
- t.done();
- } else if(iceConnectionState === 'completed') {
- const iceTransport = pc1.sctp.transport.iceTransport;
-
- assert_equals(iceTransport.state, 'completed',
- 'Expect ICE transport to be in connected state when' +
- ' iceConnectionState is completed');
- t.done();
- } else if (iceConnectionState === 'failed') {
- assert_unreached("ICE should not fail");
- }
- });
-
- pc1.createDataChannel('test');
-
- assert_equals(pc1.oniceconnectionstatechange, null,
- 'Expect connection to have iceconnectionstatechange event');
-
- pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- }, 'connection with one data channel should eventually ' +
- 'have connected connection state');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => pc1.addTrack(track, stream));
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await listenToIceConnected(pc1);
- }, 'connection with audio track should eventually ' +
- 'have connected connection state');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true, video:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => pc1.addTrack(track, stream));
-
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await listenToIceConnected(pc1);
- }, 'connection with audio and video tracks should eventually ' +
- 'have connected connection state');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- caller.addTransceiver('audio', {direction:'recvonly'});
- const stream = await getNoiseStream({audio:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- callee.addTrack(track, stream);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
-
- assert_equals(caller.getTransceivers().length, 1);
- const [transceiver] = caller.getTransceivers();
- assert_equals(transceiver.currentDirection, 'recvonly');
-
- await listenToIceConnected(caller);
- }, 'ICE can connect in a recvonly usecase');
-
- /*
- TODO
- 4.4.4 RTCIceConnectionState Enum
- failed
- Any of the RTCIceTransport s are in the failed state.
-
- disconnected
- Any of the RTCIceTransport s are in the disconnected state and none of
- them are in the failed state.
-
- closed
- The RTCPeerConnection object's [[ isClosed]] slot is true.
-
- 5.6. enum RTCIceTransportState
- new
- The RTCIceTransport is gathering candidates and/or waiting for
- remote candidates to be supplied, and has not yet started checking.
-
- failed
- The RTCIceTransport has finished gathering, received an indication that
- there are no more remote candidates, finished checking all candidate pairs,
- and all pairs have either failed connectivity checks or have lost consent.
-
- disconnected
- The ICE Agent has determined that connectivity is currently lost for this
- RTCIceTransport . This is more aggressive than failed, and may trigger
- intermittently (and resolve itself without action) on a flaky network.
- The way this state is determined is implementation dependent.
-
- Examples include:
- Losing the network interface for the connection in use.
- Repeatedly failing to receive a response to STUN requests.
-
- Alternatively, the RTCIceTransport has finished checking all existing
- candidates pairs and failed to find a connection (or consent checks
- [RFC7675] once successful, have now failed), but it is still gathering
- and/or waiting for additional remote candidates.
-
- closed
- The RTCIceTransport has shut down and is no longer responding to STUN requests.
- */
-
-for (let bundle_policy of ['balanced', 'max-bundle', 'max-compat']) {
-
-
- promise_test(async t => {
- const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
- t.add_cleanup(() => caller.close());
- const stream = await getNoiseStream(
- {audio: true, video:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track1, track2] = stream.getTracks();
- const sender1 = caller.addTrack(track1);
- const sender2 = caller.addTrack(track2);
- caller.createDataChannel('datachannel');
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- exchangeIceCandidates(caller, callee);
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
- assert_equals(sender1.transport, caller_transceiver1.sender.transport);
- await callee.setRemoteDescription(offer);
- const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- // At this point, we should have a single ICE transport, and it
- // should eventually get to the "connected" state.
- await waitForState(caller_transceiver1.receiver.transport.iceTransport,
- 'connected');
- // The PeerConnection's iceConnectionState should therefore be 'connected'
- assert_equals(caller.iceConnectionState, 'connected',
- 'PC.iceConnectionState:');
- }, 'iceConnectionState changes at the right time, with bundle policy ' +
- bundle_policy);
-}
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
- pc1.candidateBuffer = [];
- pc2.onicecandidate = e => {
- // Don't add candidate if candidate buffer is already used
- if (pc1.candidateBuffer) {
- pc1.candidateBuffer.push(e.candidate)
- }
- };
- pc1.iceStates = [pc1.iceConnectionState];
- pc2.iceStates = [pc2.iceConnectionState];
- pc1.oniceconnectionstatechange = () => {
- pc1.iceStates.push(pc1.iceConnectionState);
- };
- pc2.oniceconnectionstatechange = () => {
- pc2.iceStates.push(pc2.iceConnectionState);
- };
-
- const localStream = await getNoiseStream({audio: true, video: true});
- const localStream2 = await getNoiseStream({audio: true, video: true});
- const remoteStream = await getNoiseStream({audio: true, video: true});
- for (const stream of [localStream, localStream2, remoteStream]) {
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- }
- localStream.getTracks().forEach(t => pc1.addTrack(t, localStream));
- localStream2.getTracks().forEach(t => pc1.addTrack(t, localStream2));
- remoteStream.getTracks().forEach(t => pc2.addTrack(t, remoteStream));
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- pc1.candidateBuffer.forEach(c => pc1.addIceCandidate(c));
- delete pc1.candidateBuffer;
- await listenToIceConnected(pc1);
- await listenToIceConnected(pc2);
- // While we're waiting for pc2, pc1 may or may not have transitioned
- // to "completed" state, so allow for both cases.
- if (pc1.iceStates.length == 3) {
- assert_array_equals(pc1.iceStates, ['new', 'checking', 'connected']);
- } else {
- assert_array_equals(pc1.iceStates, ['new', 'checking', 'connected',
- 'completed']);
- }
- assert_array_equals(pc2.iceStates, ['new', 'checking', 'connected']);
-}, 'Responder ICE connection state behaves as expected');
-
-/*
- Test case for step 11 of PeerConnection.close().
- ...
- 11. Set connection's ICE connection state to "closed". This does not invoke
- the "update the ICE connection state" procedure, and does not fire any
- event.
- ...
-*/
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
-
- stream.getTracks().forEach(track => pc1.addTrack(track, stream));
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await listenToIceConnected(pc2);
-
- pc2.oniceconnectionstatechange = t.unreached_func();
- pc2.close();
- assert_equals(pc2.iceConnectionState, 'closed');
- await new Promise(r => t.step_timeout(r, 100));
-}, 'Closing a PeerConnection should not fire iceconnectionstatechange event');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.iceGatheringState</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // exchangeAnswer
- // exchangeIceCandidates
- // generateAudioReceiveOnlyOffer
-
- /*
- 4.3.2. Interface Definition
- interface RTCPeerConnection : EventTarget {
- ...
- readonly attribute RTCIceGatheringState iceGatheringState;
- attribute EventHandler onicegatheringstatechange;
- };
-
- 4.4.2. RTCIceGatheringState Enum
- enum RTCIceGatheringState {
- "new",
- "gathering",
- "complete"
- };
-
- 5.6. RTCIceTransport Interface
- interface RTCIceTransport {
- readonly attribute RTCIceGathererState gatheringState;
- ...
- };
-
- enum RTCIceGathererState {
- "new",
- "gathering",
- "complete"
- };
- */
-
- /*
- 4.4.2. RTCIceGatheringState Enum
- new
- Any of the RTCIceTransport s are in the new gathering state and
- none of the transports are in the gathering state, or there are
- no transports.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.iceGatheringState, 'new');
- }, 'Initial iceGatheringState should be new');
-
- async_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- let reachedGathering = false;
- const onIceGatheringStateChange = t.step_func(() => {
- const { iceGatheringState } = pc;
-
- if(iceGatheringState === 'gathering') {
- reachedGathering = true;
- } else if(iceGatheringState === 'complete') {
- assert_true(reachedGathering, 'iceGatheringState should reach gathering before complete');
- t.done();
- }
- });
-
- assert_equals(pc.onicegatheringstatechange, null,
- 'Expect connection to have icegatheringstatechange event');
- assert_equals(pc.iceGatheringState, 'new');
-
- pc.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
-
- generateAudioReceiveOnlyOffer(pc)
- .then(offer => pc.setLocalDescription(offer))
- .then(err => t.step_func(err =>
- assert_unreached(`Unhandled rejection ${err.name}: ${err.message}`)));
- }, 'iceGatheringState should eventually become complete after setLocalDescription');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await initialOfferAnswerWithIceGatheringStateTransitions(
- pc1, pc2);
-
- expectNoMoreGatheringStateChanges(t, pc1);
- expectNoMoreGatheringStateChanges(t, pc2);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setLocalDescription(await pc2.createOffer());
-
- await new Promise(r => t.step_timeout(r, 500));
- }, 'setLocalDescription(reoffer) with no new transports should not cause iceGatheringState to change');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- expectNoMoreGatheringStateChanges(t, pc1);
-
- await pc1.setLocalDescription(await pc1.createOffer());
-
- await new Promise(r => t.step_timeout(r, 500));
- }, 'setLocalDescription() with no transports should not cause iceGatheringState to change');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await initialOfferAnswerWithIceGatheringStateTransitions(
- pc1, pc2);
- await pc1.setLocalDescription(await pc1.createOffer({iceRestart: true}));
- await iceGatheringStateTransitions(pc1, 'gathering', 'complete');
- }, 'setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to "checking" and then "complete"');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- expectNoMoreGatheringStateChanges(t, pc2);
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc2.setRemoteDescription(offer);
- await pc2.setRemoteDescription({type: 'rollback'});
- await pc2.setRemoteDescription(offer);
- }, 'sRD does not cause ICE gathering state changes');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await initialOfferAnswerWithIceGatheringStateTransitions(
- pc1, pc2);
-
- const pc1waiter = iceGatheringStateTransitions(pc1, 'new');
- const pc2waiter = iceGatheringStateTransitions(pc2, 'new');
- pc1.getTransceivers()[0].stop();
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- assert_equals(pc2.getTransceivers().length, 0,
- 'PC2 transceivers should be invisible after negotiation');
- assert_equals(pc2.iceGatheringState, 'new');
- await pc2waiter;
- await pc1.setRemoteDescription(pc2.localDescription);
- assert_equals(pc1.getTransceivers().length, 0,
- 'PC1 transceivers should be invisible after negotiation');
- assert_equals(pc1.iceGatheringState, 'new');
- await pc1waiter;
- }, 'renegotiation that closes all transports should result in ICE gathering state "new"');
-
- /*
- 4.3.2. RTCIceGatheringState Enum
- new
- Any of the RTCIceTransports are in the "new" gathering state and none
- of the transports are in the "gathering" state, or there are no
- transports.
-
- gathering
- Any of the RTCIceTransport s are in the gathering state.
-
- complete
- At least one RTCIceTransport exists, and all RTCIceTransports are
- in the completed gathering state.
-
- 5.6. RTCIceGathererState
- gathering
- The RTCIceTransport is in the process of gathering candidates.
-
- complete
- The RTCIceTransport has completed gathering and the end-of-candidates
- indication for this transport has been sent. It will not gather candidates
- again until an ICE restart causes it to restart.
- */
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- const onIceGatheringStateChange = t.step_func(() => {
- const { iceGatheringState } = pc2;
-
- if(iceGatheringState === 'gathering') {
- const iceTransport = pc2.sctp.transport.iceTransport;
-
- assert_equals(iceTransport.gatheringState, 'gathering',
- 'Expect ICE transport to be in gathering gatheringState when iceGatheringState is gathering');
-
- } else if(iceGatheringState === 'complete') {
- const iceTransport = pc2.sctp.transport.iceTransport;
-
- assert_equals(iceTransport.gatheringState, 'complete',
- 'Expect ICE transport to be in complete gatheringState when iceGatheringState is complete');
-
- t.done();
- }
- });
-
- pc1.createDataChannel('test');
-
- // Spec bug w3c/webrtc-pc#1382
- // Because sctp is only defined when answer is set, we listen
- // to pc2 so that we can be confident that sctp is defined
- // when icegatheringstatechange event is fired.
- pc2.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
-
-
- exchangeIceCandidates(pc1, pc2);
-
- await pc1.setLocalDescription();
- assert_equals(pc1.sctp.transport.iceTransport.gatheringState, 'new');
- await pc2.setRemoteDescription(pc1.localDescription);
-
- await exchangeAnswer(pc1, pc2);
- }, 'connection with one data channel should eventually have connected connection state');
-
- /*
- TODO
- 5.6. RTCIceTransport Interface
- new
- The RTCIceTransport was just created, and has not started gathering
- candidates yet.
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>Mandatory-to-implement stats compliance (a subset of webrtc-stats)</title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCStats-helper.js"></script>
-<script>
-'use strict';
-
-// From https://w3c.github.io/webrtc-pc/#mandatory-to-implement-stats
-
-const mandatory = {
- RTCRtpStreamStats: [
- "ssrc",
- "kind",
- "transportId",
- "codecId",
- ],
- RTCReceivedRtpStreamStats: [
- "packetsReceived",
- "packetsLost",
- "jitter",
- "framesDropped"
- ],
- RTCInboundRtpStreamStats: [
- "remoteId",
- "framesDecoded",
- "nackCount",
- "framesReceived",
- "bytesReceived",
- "totalAudioEnergy",
- "totalSamplesDuration",
- "packetsDiscarded"
- ],
- RTCRemoteInboundRtpStreamStats: [
- "localId",
- "roundTripTime",
- ],
- RTCSentRtpStreamStats: [
- "packetsSent",
- "bytesSent"
- ],
- RTCOutboundRtpStreamStats: [
- "remoteId",
- "framesEncoded",
- "nackCount",
- "framesSent"
- ],
- RTCRemoteOutboundRtpStreamStats: [
- "localId",
- "remoteTimestamp",
- ],
- RTCPeerConnectionStats: [
- "dataChannelsOpened",
- "dataChannelsClosed",
- ],
- RTCDataChannelStats: [
- "label",
- "protocol",
- "dataChannelIdentifier",
- "state",
- "messagesSent",
- "bytesSent",
- "messagesReceived",
- "bytesReceived",
- ],
- RTCMediaSourceStats: [
- "trackIdentifier",
- "kind"
- ],
- RTCAudioSourceStats: [
- "totalAudioEnergy",
- "totalSamplesDuration"
- ],
- RTCVideoSourceStats: [
- "width",
- "height",
- "framesPerSecond"
- ],
- RTCCodecStats: [
- "payloadType",
- /* codecType is part of MTI but is not systematically set
- per https://www.w3.org/TR/webrtc-stats/#dom-rtccodecstats-codectype
- If the dictionary member is not present, it means that
- this media format can be both encoded and decoded. */
- // "codecType",
- "mimeType",
- "clockRate",
- "channels",
- "sdpFmtpLine",
- ],
- RTCTransportStats: [
- "bytesSent",
- "bytesReceived",
- "selectedCandidatePairId",
- "localCertificateId",
- "remoteCertificateId",
- ],
- RTCIceCandidatePairStats: [
- "transportId",
- "localCandidateId",
- "remoteCandidateId",
- "state",
- "nominated",
- "bytesSent",
- "bytesReceived",
- "totalRoundTripTime",
- "currentRoundTripTime"
- ],
- RTCIceCandidateStats: [
- "address",
- "port",
- "protocol",
- "candidateType",
- ],
- RTCCertificateStats: [
- "fingerprint",
- "fingerprintAlgorithm",
- "base64Certificate",
- /* issuerCertificateId is part of MTI but is not systematically set
- per https://www.w3.org/TR/webrtc-stats/#dom-rtccertificatestats-issuercertificateid
- If the current certificate is at the end of the chain
- (i.e. a self-signed certificate), this will not be set. */
- // "issuerCertificateId",
- ],
-};
-
-// From https://w3c.github.io/webrtc-stats/webrtc-stats.html#rtcstatstype-str*
-
-const dictionaryNames = {
- "codec": "RTCCodecStats",
- "inbound-rtp": "RTCInboundRtpStreamStats",
- "outbound-rtp": "RTCOutboundRtpStreamStats",
- "remote-inbound-rtp": "RTCRemoteInboundRtpStreamStats",
- "remote-outbound-rtp": "RTCRemoteOutboundRtpStreamStats",
- "csrc": "RTCRtpContributingSourceStats",
- "peer-connection": "RTCPeerConnectionStats",
- "data-channel": "RTCDataChannelStats",
- "media-source": {
- audio: "RTCAudioSourceStats",
- video: "RTCVideoSourceStats"
- },
- "track": {
- video: "RTCSenderVideoTrackAttachmentStats",
- audio: "RTCSenderAudioTrackAttachmentStats"
- },
- "sender": {
- audio: "RTCAudioSenderStats",
- video: "RTCVideoSenderStats"
- },
- "receiver": {
- audio: "RTCAudioReceiverStats",
- video: "RTCVideoReceiverStats",
- },
- "transport": "RTCTransportStats",
- "candidate-pair": "RTCIceCandidatePairStats",
- "local-candidate": "RTCIceCandidateStats",
- "remote-candidate": "RTCIceCandidateStats",
- "certificate": "RTCCertificateStats",
-};
-
-// From https://w3c.github.io/webrtc-stats/webrtc-stats.html (webidl)
-
-const parents = {
- RTCVideoSourceStats: "RTCMediaSourceStats",
- RTCAudioSourceStats: "RTCMediaSourceStats",
- RTCReceivedRtpStreamStats: "RTCRtpStreamStats",
- RTCInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
- RTCRemoteInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
- RTCSentRtpStreamStats: "RTCRtpStreamStats",
- RTCOutboundRtpStreamStats: "RTCSentRtpStreamStats",
- RTCRemoteOutboundRtpStreamStats : "RTCSentRtpStreamStats",
-};
-
-const remaining = JSON.parse(JSON.stringify(mandatory));
-for (const dictName in remaining) {
- remaining[dictName] = new Set(remaining[dictName]);
-}
-
-async function getAllStats(t, pc) {
- // Try to obtain as many stats as possible, waiting up to 20 seconds for
- // roundTripTime which can take several RTCP messages to calculate.
- let stats;
- for (let i = 0; i < 20; i++) {
- stats = await pc.getStats();
- const values = [...stats.values()];
- const [audio, video] = ["audio", "video"].map(kind =>
- values.find(s => s.type == "remote-inbound-rtp" && s.kind == kind));
- if (audio && "roundTripTime" in audio &&
- video && "roundTripTime" in video) {
- return stats;
- }
- await new Promise(r => t.step_timeout(r, 1000));
- }
- return stats;
-}
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel("dummy", {negotiated: true, id: 0});
- const dc2 = pc2.createDataChannel("dummy", {negotiated: true, id: 0});
-
- const stream = await getNoiseStream({video: true, audio:true});
- for (const track of stream.getTracks()) {
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
- t.add_cleanup(() => track.stop());
- }
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- const stats = await getAllStats(t, pc1);
-
- // The focus of this test is not API correctness, but rather to provide an
- // accessible metric of implementation progress by dictionary member. We count
- // whether we've seen each dictionary's mandatory members in getStats().
-
- test(t => {
- for (const stat of stats.values()) {
- let dictName = dictionaryNames[stat.type];
- if (!dictName) continue;
- if (typeof dictName == "object") {
- dictName = dictName[stat.kind];
- }
-
- assert_equals(typeof dictName, "string", "Test error. String.");
- if (dictName && mandatory[dictName]) {
- do {
- const memberNames = mandatory[dictName];
- const remainingNames = remaining[dictName];
- assert_true(memberNames.length > 0, "Test error. Parent not found.");
- for (const memberName of memberNames) {
- if (memberName in stat) {
- assert_not_equals(stat[memberName], undefined, "Not undefined");
- remainingNames.delete(memberName);
- }
- }
- dictName = parents[dictName];
- } while (dictName);
- }
- }
- }, "Validating stats");
-
- for (const dictName in mandatory) {
- for (const memberName of mandatory[dictName]) {
- test(t => {
- assert_true(!remaining[dictName].has(memberName),
- `Is ${memberName} present`);
- }, `${dictName}'s ${memberName}`);
- }
- }
-}, 'getStats succeeds');
-
-</script>
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.ondatachannel</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// exchangeIceCandidates
-// exchangeOfferAnswer
-// createDataChannelPair
-
-/*
- 6.2. RTCDataChannel
- When an underlying data transport is to be announced (the other peer created a channel with
- negotiated unset or set to false), the user agent of the peer that did not initiate the
- creation process MUST queue a task to run the following steps:
- 2. Let channel be a newly created RTCDataChannel object.
- 7. Set channel's [[ReadyState]] to open (but do not fire the open event, yet).
- 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
-
- 6.3. RTCDataChannelEvent
- Firing a datachannel event named e with an RTCDataChannel channel means that an event with the
- name e, which does not bubble (except where otherwise stated) and is not cancelable (except
- where otherwise stated), and which uses the RTCDataChannelEvent interface with the channel
- attribute set to channel, MUST be created and dispatched at the given target.
-
- interface RTCDataChannelEvent : Event {
- readonly attribute RTCDataChannel channel;
- };
- */
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- let eventCount = 0;
-
- pc2.ondatachannel = t.step_func((event) => {
- eventCount++;
- assert_equals(eventCount, 1,
- 'Expect data channel event to fire exactly once');
-
- assert_true(event instanceof RTCDataChannelEvent,
- 'Expect event to be instance of RTCDataChannelEvent');
-
- assert_equals(event.bubbles, false);
- assert_equals(event.cancelable, false);
-
- const dc = event.channel;
- assert_true(dc instanceof RTCDataChannel,
- 'Expect channel to be instance of RTCDataChannel');
-
- // The channel should be in the 'open' state already.
- // See: https://github.com/w3c/webrtc-pc/pull/1851
- assert_equals(dc.readyState, 'open',
- 'Expect channel ready state to be open');
-
- resolver.resolve();
- });
-
- pc1.createDataChannel('fire-me!');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'Data channel event should fire when new data channel is announced to the remote peer');
-
-/*
- Since the channel should be in the 'open' state when dispatching via the 'datachannel' event,
- we should be able to send data in the event handler.
- */
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const message = 'meow meow!';
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc2 = event.channel;
- dc2.send(message);
- });
-
- const dc1 = pc1.createDataChannel('fire-me!');
- dc1.onmessage = t.step_func((event) => {
- assert_equals(event.data, message,
- 'Received data should be equal to sent data');
-
- resolver.resolve();
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'Should be able to send data in a datachannel event handler');
-
-/*
- 6.2. RTCDataChannel
- When an underlying data transport is to be announced (the other peer created a channel with
- negotiated unset or set to false), the user agent of the peer that did not initiate the
- creation process MUST queue a task to run the following steps:
- 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
- 9. If the channel's [[ReadyState]] is still open, announce the data channel as open.
- */
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc = event.channel;
- dc.onopen = t.step_func(() => {
- assert_unreached('Open event should not fire');
- });
-
- // This should prevent triggering the 'open' event
- dc.close();
-
- // Wait a bit to ensure the 'open' event does NOT fire
- t.step_timeout(() => resolver.resolve(), 500);
- });
-
- pc1.createDataChannel('fire-me!');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'Open event should not be raised when closing the channel in the datachannel event');
-
-// Added this test as a result of the discussion in
-// https://github.com/w3c/webrtc-pc/pull/1851#discussion_r185976747
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc = event.channel;
- dc.onopen = t.step_func((event) => {
- resolver.resolve();
- });
-
- // This should NOT prevent triggering the 'open' event since it enqueues at least two tasks
- t.step_timeout(() => {
- t.step_timeout(() => {
- dc.close()
- }, 1);
- }, 1);
- });
-
- pc1.createDataChannel('fire-me!');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'Open event should be raised when closing the channel in the datachannel event after ' +
- 'enqueuing a task');
-
-
-/*
- Combination of the two tests above (send and close).
- */
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const message = 'meow meow!';
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc2 = event.channel;
- dc2.onopen = t.step_func(() => {
- assert_unreached('Open event should not fire');
- });
-
- // This should send but still prevent triggering the 'open' event
- dc2.send(message);
- dc2.close();
- });
-
- const dc1 = pc1.createDataChannel('fire-me!');
- dc1.onmessage = t.step_func((event) => {
- assert_equals(event.data, message,
- 'Received data should be equal to sent data');
-
- resolver.resolve();
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'Open event should not be raised when sending and immediately closing the channel in the ' +
- 'datachannel event');
-
-/*
- 6.2. RTCDataChannel
-
- interface RTCDataChannel : EventTarget {
- readonly attribute USVString label;
- readonly attribute boolean ordered;
- readonly attribute unsigned short? maxPacketLifeTime;
- readonly attribute unsigned short? maxRetransmits;
- readonly attribute USVString protocol;
- readonly attribute boolean negotiated;
- readonly attribute unsigned short? id;
- readonly attribute RTCDataChannelState readyState;
- ...
- };
-
- When an underlying data transport is to be announced (the other peer created a channel with
- negotiated unset or set to false), the user agent of the peer that did not initiate the
- creation process MUST queue a task to run the following steps:
- 2. Let channel be a newly created RTCDataChannel object.
- 3. Let configuration be an information bundle received from the other peer as a part of the
- process to establish the underlying data transport described by the WebRTC DataChannel
- Protocol specification [RTCWEB-DATA-PROTOCOL].
- 4. Initialize channel's [[DataChannelLabel]], [[Ordered]], [[MaxPacketLifeTime]],
- [[MaxRetransmits]], [[DataChannelProtocol]], and [[DataChannelId]] internal slots to the
- corresponding values in configuration.
- 5. Initialize channel's [[Negotiated]] internal slot to false.
- 7. Set channel's [[ReadyState]] slot to connecting.
- 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
-
- Note: More exhaustive tests are defined in RTCDataChannel-dcep
- */
-
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel('test', {
- ordered: false,
- maxRetransmits: 1,
- protocol: 'custom'
- });
-
- assert_equals(dc1.label, 'test');
- assert_equals(dc1.ordered, false);
- assert_equals(dc1.maxPacketLifeTime, null);
- assert_equals(dc1.maxRetransmits, 1);
- assert_equals(dc1.protocol, 'custom');
- assert_equals(dc1.negotiated, false);
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc2 = event.channel;
- assert_true(dc2 instanceof RTCDataChannel,
- 'Expect channel to be instance of RTCDataChannel');
-
- assert_equals(dc2.label, 'test');
- assert_equals(dc2.ordered, false);
- assert_equals(dc2.maxPacketLifeTime, null);
- assert_equals(dc2.maxRetransmits, 1);
- assert_equals(dc2.protocol, 'custom');
- assert_equals(dc2.negotiated, false);
- assert_equals(dc2.id, dc1.id);
-
- resolver.resolve();
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'In-band negotiated channel created on remote peer should match the same configuration as local ' +
- 'peer');
-
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const dc1 = pc1.createDataChannel('');
-
- assert_equals(dc1.label, '');
- assert_equals(dc1.ordered, true);
- assert_equals(dc1.maxPacketLifeTime, null);
- assert_equals(dc1.maxRetransmits, null);
- assert_equals(dc1.protocol, '');
- assert_equals(dc1.negotiated, false);
-
- pc2.ondatachannel = t.step_func((event) => {
- const dc2 = event.channel;
- assert_true(dc2 instanceof RTCDataChannel,
- 'Expect channel to be instance of RTCDataChannel');
-
- assert_equals(dc2.label, '');
- assert_equals(dc2.ordered, true);
- assert_equals(dc2.maxPacketLifeTime, null);
- assert_equals(dc2.maxRetransmits, null);
- assert_equals(dc2.protocol, '');
- assert_equals(dc2.negotiated, false);
- assert_equals(dc2.id, dc1.id);
-
- resolver.resolve();
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- await resolver;
-}, 'In-band negotiated channel created on remote peer should match the same (default) ' +
- 'configuration as local peer');
-
-/*
- 6.2. RTCDataChannel
- Dictionary RTCDataChannelInit Members
- negotiated
- The default value of false tells the user agent to announce the
- channel in-band and instruct the other peer to dispatch a corresponding
- RTCDataChannel object. If set to true, it is up to the application
- to negotiate the channel and create a RTCDataChannel object with the
- same id at the other peer.
- */
-promise_test(async (t) => {
- const resolver = new Resolver();
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc2.ondatachannel = t.unreached_func('datachannel event should not be fired');
-
- pc1.createDataChannel('test', {
- negotiated: true,
- id: 42
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- // Wait a bit to ensure the 'datachannel' event does NOT fire
- t.step_timeout(() => resolver.resolve(), 500);
- await resolver;
-}, 'Negotiated channel should not fire datachannel event on remote peer');
-
-/*
- Non-testable
- 6.2. RTCDataChannel
- When an underlying data transport is to be announced
- 1. If the associated RTCPeerConnection object's [[isClosed]] slot
- is true, abort these steps.
-
- The above step is not testable because to reach it we would have to
- close the peer connection just between receiving the in-band negotiated data
- channel via DCEP and firing the datachannel event.
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.onicecandidateerror</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-
-promise_test(async t => {
- const config = {
- iceServers: [{urls: "turn:123", username: "123", credential: "123"}]
- };
- const pc = new RTCPeerConnection(config);
- t.add_cleanup(() => pc.close());
- const onErrorPromise = addEventListenerPromise(t, pc, 'icecandidateerror', event => {
- assert_true(event instanceof RTCPeerConnectionIceErrorEvent,
- 'Expect event to be instance of RTCPeerConnectionIceErrorEvent');
- // Do not hardcode any specific errors here. Instead only verify
- // that all the fields contain something expected.
- // Testing of event.errorText can be added later once it's content is
- // specified in spec with more detail.
- assert_true(event.errorCode >= 300 && event.errorCode <= 799, "errorCode");
- if (event.port == 0) {
- assert_equals(event.address, null);
- } else {
- assert_true(event.address.includes(".") || event.address.includes(":"));
- }
- assert_true(event.url.includes("123"), "url");
- });
- const stream = await getNoiseStream({audio:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc.addTrack(stream.getAudioTracks()[0], stream);
- await pc.setLocalDescription(await pc.createOffer());
- await onErrorPromise;
-}, 'Surfacing onicecandidateerror');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>Test RTCPeerConnection.prototype.onnegotiationneeded</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateOffer
- // generateAnswer
- // generateAudioReceiveOnlyOffer
- // test_never_resolve
-
- // Listen to the negotiationneeded event on a peer connection
- // Returns a promise that resolves when the first event is fired.
- // The resolve result is a dictionary with event and nextPromise,
- // which resolves when the next negotiationneeded event is fired.
- // This allow us to promisify the event listening and assert whether
- // an event is fired or not by testing whether a promise is resolved.
- function awaitNegotiation(pc) {
- if(pc.onnegotiationneeded) {
- throw new Error('connection is already attached with onnegotiationneeded event handler');
- }
-
- function waitNextNegotiation() {
- return new Promise(resolve => {
- pc.onnegotiationneeded = event => {
- const nextPromise = waitNextNegotiation();
- resolve({ nextPromise, event });
- }
- });
- }
-
- return waitNextNegotiation();
- }
-
- // Return a promise that rejects if the first promise is resolved before second promise.
- // Also rejects when either promise rejects.
- function assert_first_promise_fulfill_after_second(promise1, promise2, message) {
- if(!message) {
- message = 'first promise is resolved before second promise';
- }
-
- return new Promise((resolve, reject) => {
- let secondResolved = false;
-
- promise1.then(() => {
- if(secondResolved) {
- resolve();
- } else {
- assert_unreached(message);
- }
- })
- .catch(reject);
-
- promise2.then(() => {
- secondResolved = true;
- }, reject);
- });
- }
-
- /*
- 4.7.3. Updating the Negotiation-Needed flag
-
- To update the negotiation-needed flag
- 5. Set connection's [[needNegotiation]] slot to true.
- 6. Queue a task that runs the following steps:
- 3. Fire a simple event named negotiationneeded at connection.
-
- To check if negotiation is needed
- 2. If connection has created any RTCDataChannels, and no m= section has
- been negotiated yet for data, return "true".
-
- 6.1. RTCPeerConnection Interface Extensions
-
- createDataChannel
- 14. If channel was the first RTCDataChannel created on connection,
- update the negotiation-needed flag for connection.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const negotiated = awaitNegotiation(pc);
-
- pc.createDataChannel('test');
- return negotiated;
- }, 'Creating first data channel should fire negotiationneeded event');
-
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- const negotiated = awaitNegotiation(pc);
-
- pc.createDataChannel('foo');
- return negotiated
- .then(({nextPromise}) => {
- pc.createDataChannel('bar');
- return nextPromise;
- });
- }, 'calling createDataChannel twice should fire negotiationneeded event once');
-
- /*
- 4.7.3. Updating the Negotiation-Needed flag
- To check if negotiation is needed
- 3. For each transceiver t in connection's set of transceivers, perform
- the following checks:
- 1. If t isn't stopped and isn't yet associated with an m= section
- according to [JSEP] (section 3.4.1.), return "true".
-
- 5.1. RTCPeerConnection Interface Extensions
- addTransceiver
- 9. Update the negotiation-needed flag for connection.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const negotiated = awaitNegotiation(pc);
-
- pc.addTransceiver('audio');
- return negotiated;
- }, 'addTransceiver() should fire negotiationneeded event');
-
- /*
- 4.7.3. Updating the Negotiation-Needed flag
- To update the negotiation-needed flag
- 4. If connection's [[needNegotiation]] slot is already true, abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- const negotiated = awaitNegotiation(pc);
-
- pc.addTransceiver('audio');
- return negotiated
- .then(({nextPromise}) => {
- pc.addTransceiver('video');
- return nextPromise;
- });
- }, 'Calling addTransceiver() twice should fire negotiationneeded event once');
-
- /*
- 4.7.3. Updating the Negotiation-Needed flag
- To update the negotiation-needed flag
- 4. If connection's [[needNegotiation]] slot is already true, abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- const negotiated = awaitNegotiation(pc);
-
- pc.createDataChannel('test');
- return negotiated
- .then(({nextPromise}) => {
- pc.addTransceiver('video');
- return nextPromise;
- });
- }, 'Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once');
-
- /*
- 4.7.3. Updating the Negotiation-Needed flag
- To update the negotiation-needed flag
- 2. If connection's signaling state is not "stable", abort these steps.
- */
- test_never_resolve(t => {
- const pc = new RTCPeerConnection();
- let negotiated;
-
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer => {
- pc.setLocalDescription(offer);
- negotiated = awaitNegotiation(pc);
- })
- .then(() => negotiated)
- .then(({nextPromise}) => {
- assert_equals(pc.signalingState, 'have-local-offer');
- pc.createDataChannel('test');
- return nextPromise;
- });
- }, 'negotiationneeded event should not fire if signaling state is not stable');
-
- /*
- 4.4.1.6. Set the RTCSessionSessionDescription
- 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:
- 2. If connection's [[NegotiationNeeded]] slot is false, abort these steps.
- 3. Fire a simple event named negotiationneeded at connection.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio');
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- let fired = false;
- pc.onnegotiationneeded = e => fired = true;
- pc.createDataChannel('test');
- await pc.setRemoteDescription(await generateAnswer(offer));
- await undefined;
- assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after SRD success");
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- }, 'negotiationneeded event should fire only after signaling state goes back to stable after setRemoteDescription');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio');
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
-
- let fired = false;
- pc.onnegotiationneeded = e => fired = true;
- await pc.setRemoteDescription(await generateOffer());
- pc.createDataChannel('test');
- await pc.setLocalDescription(await pc.createAnswer());
- await undefined;
- assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after SLD success");
-
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- }, 'negotiationneeded event should fire only after signaling state goes back to stable after setLocalDescription');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio');
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- let fired = false;
- pc.onnegotiationneeded = e => fired = true;
- pc.createDataChannel('test');
- const p = pc.setRemoteDescription(await generateAnswer(offer));
- await new Promise(resolve => pc.onsignalingstatechange = resolve);
- assert_false(fired, "negotiationneeded should not fire before signalingstatechange fires");
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- await p;
- }, 'negotiationneeded event should fire only after signalingstatechange event fires from setRemoteDescription');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio');
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
-
- let fired = false;
- pc.onnegotiationneeded = e => fired = true;
- await pc.setRemoteDescription(await generateOffer());
- pc.createDataChannel('test');
-
- const p = pc.setLocalDescription(await pc.createAnswer());
- await new Promise(resolve => pc.onsignalingstatechange = resolve);
- assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after returning to stable");
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- await p;
- }, 'negotiationneeded event should fire only after signalingstatechange event fires from setLocalDescription');
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
-
- addTrack
- 10. Update the negotiation-needed flag for connection.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- pc.addTrack(track, stream);
-
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- }, 'addTrack should cause negotiationneeded to fire');
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
-
- removeTrack
- 12. Update the negotiation-needed flag for connection.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- pc.onnegotiationneeded = t.step_func(() => {
- assert_unreached('onnegotiationneeded misfired');
- });
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
-
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
-
- pc.removeTrack(sender);
- await new Promise(resolve => pc.onnegotiationneeded = resolve)
- }, 'removeTrack should cause negotiationneeded to fire on the caller');
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
-
- removeTrack
- 12. Update the negotiation-needed flag for connection.
- */
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- caller.addTransceiver('audio', {direction:'recvonly'});
- const offer = await caller.createOffer();
-
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = callee.addTrack(track, stream);
-
- await new Promise(resolve => callee.onnegotiationneeded = resolve);
- callee.onnegotiationneeded = t.step_func(() => {
- assert_unreached('onnegotiationneeded misfired');
- });
-
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- callee.setLocalDescription(answer);
-
- callee.removeTrack(sender);
- await new Promise(resolve => callee.onnegotiationneeded = resolve)
- }, 'removeTrack should cause negotiationneeded to fire on the callee');
-
- /*
- 5.4. RTCRtpTransceiver Interface
-
- setDirection
- 7. Update the negotiation-needed flag for connection.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio', {direction:'sendrecv'});
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
- transceiver.direction = 'recvonly';
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- }, 'Updating the direction of the transceiver should cause negotiationneeded to fire');
-
- /*
- 5.2. RTCRtpSender Interface
-
- setStreams
- 7. Update the negotiation-needed flag for connection.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver('audio', {direction:'sendrecv'});
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
-
- const stream = new MediaStream();
- transceiver.sender.setStreams(stream);
- await new Promise(resolve => pc.onnegotiationneeded = resolve);
- }, 'Calling setStreams should cause negotiationneeded to fire');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- let negotiationCount = 0;
- pc1.onnegotiationneeded = async () => {
- negotiationCount++;
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
- }
-
- pc1.addTransceiver("video");
- await new Promise(r => pc1.onsignalingstatechange = () => pc1.signalingState == "stable" && r());
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onsignalingstatechange = () => pc1.signalingState == "stable" && r());
- assert_equals(negotiationCount, 2);
- }, 'Adding two transceivers, one at a time, results in the expected number of negotiationneeded events');
-
- /*
- TODO
- 4.7.3. Updating the Negotiation-Needed flag
-
- To update the negotiation-needed flag
- 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.
- 6. Queue a task that runs the following steps:
- 2. If connection's [[needNegotiation]] slot is false, abort these steps.
-
- To check if negotiation is needed
- 3. For each transceiver t in connection's set of transceivers, perform
- the following checks:
- 2. If t isn't stopped and is associated with an m= section according
- to [JSEP] (section 3.4.1.), then perform the following checks:
- 1. If t's direction is "sendrecv" or "sendonly", and the
- associated m= section in connection's currentLocalDescription
- doesn't contain an "a=msid" line, return "true".
- 2. If connection's currentLocalDescription if of type "offer",
- and the direction of the associated m= section in neither the
- offer nor answer matches t's direction, return "true".
- 3. If connection's currentLocalDescription if of type "answer",
- and the direction of the associated m= section in the answer
- does not match t's direction intersected with the offered
- direction (as described in [JSEP] (section 5.3.1.)),
- return "true".
- 3. If t is stopped and is associated with an m= section according
- to [JSEP] (section 3.4.1.), but the associated m= section is
- not yet rejected in connection's currentLocalDescription or
- currentRemoteDescription , return "true".
- 4. If all the preceding checks were performed and "true" was not returned,
- nothing remains to be negotiated; return "false".
-
- 4.3.1. RTCPeerConnection Operation
-
- When the RTCPeerConnection() constructor is invoked
- 7. Let connection have a [[needNegotiation]] internal slot, initialized to false.
-
- 5.4. RTCRtpTransceiver Interface
-
- 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>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection onsignalingstatechanged</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-
-promise_test(async t => {
- const [track] = (await getNoiseStream({video: true})).getTracks();
- t.add_cleanup(() => track.stop());
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTrack(track, new MediaStream());
- await pc1.setLocalDescription(await pc1.createOffer());
- const events = [];
- pc2.onsignalingstatechange = t.step_func(e => {
- const [transceiver] = pc2.getTransceivers();
- assert_equals(transceiver.currentDirection, null);
- events.push(pc2.signalingState);
- });
- await pc2.setRemoteDescription(pc1.localDescription);
- assert_equals(events.length, 1, "event fired");
- assert_equals(events[0], "have-remote-offer");
-
- pc2.onsignalingstatechange = t.step_func(e => {
- const [transceiver] = pc2.getTransceivers();
- assert_equals(transceiver.currentDirection, "recvonly");
- events.push(pc2.signalingState);
- });
- await pc2.setLocalDescription(await pc2.createAnswer());
- assert_equals(events.length, 2, "event fired");
- assert_equals(events[1], "stable");
-}, 'Negotiation methods fire signalingstatechange events');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
-
- stream.getTracks().forEach(track => pc1.addTrack(track, stream));
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await listenToIceConnected(pc2);
-
- pc2.onsignalingstatechange = t.unreached_func();
- pc2.close();
- assert_equals(pc2.signalingState, 'closed');
- await new Promise(r => t.step_timeout(r, 100));
-}, 'Closing a PeerConnection should not fire signalingstatechange event');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc2.addTransceiver('video');
-
- pc1.ontrack = t.unreached_func();
- pc1.onsignalingstatechange = t.step_func(e => {
- pc1.ontrack = null;
- });
- await pc1.setRemoteDescription(await pc2.createOffer());
-}, 'signalingstatechange is the first event to fire');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.ontrack</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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.
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- // Fail the test if the ontrack event handler is not implemented
- 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=sendonly
-a=rtpmap:111 opus/48000/2
-a=msid:stream1 track1
-a=ssrc:1001 cname:some
-`;
-
- const trackEventPromise = addEventListenerPromise(t, pc, 'track');
- await pc.setRemoteDescription({ type: 'offer', sdp });
- const trackEvent = await trackEventPromise;
- 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)');
- }, 'setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed.');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- 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');
-
- await pc.setRemoteDescription({ type: 'offer', sdp });
- await new Promise(resolve => t.step_timeout(resolve, 100));
- }, 'setRemoteDescription() with m= line of recvonly direction should not trigger track event');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- const [track, mediaStream] = await getTrackFromUserMedia('audio');
- pc1.addTrack(track, mediaStream);
- const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
- await pc2.setRemoteDescription(await pc1.createOffer());
- const trackEvent = await trackEventPromise;
-
- assert_equals(trackEvent.track.kind, 'audio',
- 'Expect track.kind to be audio');
-
- validateTrackEvent(trackEvent);
- }, 'addTrack() should cause remote connection to fire ontrack when setRemoteDescription()');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('video');
-
- const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
- await pc2.setRemoteDescription(await pc1.createOffer());
- const trackEvent = await trackEventPromise;
- const { track } = trackEvent;
-
- assert_equals(track.kind, 'video',
- 'Expect track.kind to be video');
-
- validateTrackEvent(trackEvent);
- }, `addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'inactive' });
- pc2.ontrack = t.unreached_func('ontrack event should not fire for track with inactive direction');
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- await new Promise(resolve => t.step_timeout(resolve, 100));
- }, `addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()`);
-
- ["audio", "video"].forEach(type => promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const checkNoUnexpectedTrack = ({track}) => {
- assert_equals(track.kind, type, `ontrack event should not fire for ${track.kind}`);
- };
-
- pc2.ontrack = t.step_func(checkNoUnexpectedTrack);
- pc1.ontrack = t.step_func(checkNoUnexpectedTrack);
-
- await pc1.setLocalDescription(await pc1.createOffer(
- { offerToReceiveVideo: true, offerToReceiveAudio: true }));
-
- pc2.addTrack(...await getTrackFromUserMedia(type));
-
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
-
- await new Promise(resolve => t.step_timeout(resolve, 100));
- }, `Using offerToReceiveAudio and offerToReceiveVideo should only cause a ${type} track event to fire, if ${type} was the only type negotiated`));
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script>
-'use strict';
-
-// Helpers to test APIs "return a promise rejected with a newly created" error.
-// Strictly speaking this means already-rejected upon return.
-function promiseState(p) {
- const t = {};
- return Promise.race([p, t])
- .then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
-}
-
-// However, to allow promises to be used in implementations, this helper adds
-// some slack: returning a pending promise will pass, provided it is rejected
-// before the end of the current run of the event loop (i.e. on microtask queue
-// before next task).
-async function promiseStateFinal(p) {
- for (let i = 0; i < 20; i++) {
- await promiseState(p);
- }
- return promiseState(p);
-}
-
-[promiseState, promiseStateFinal].forEach(f => promise_test(async t => {
- assert_equals(await f(Promise.resolve()), "fulfilled");
- assert_equals(await f(Promise.reject()), "rejected");
- assert_equals(await f(new Promise(() => {})), "pending");
-}, `${f.name} helper works`));
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {track} = new RTCPeerConnection().addTransceiver("audio").receiver;
- assert_not_equals(track, null);
- const p = pc.getStats(track);
- const haveState = promiseStateFinal(p);
- try {
- await p;
- assert_unreached("Control. Must not succeed");
- } catch (e) {
- assert_equals(e.name, "InvalidAccessError");
- }
- assert_equals(await haveState, "rejected", "promise rejected on same task");
-}, "pc.getStats must detect InvalidAccessError synchronously always");
-
-// Helper builds on above tests to check if operations queue is empty or not.
-//
-// Meaning of "empty": Because this helper uses the sloppy promiseStateFinal,
-// it may not detect operations on the chain unless they block the current run
-// of the event loop. In other words, it may not detect operations on the chain
-// that resolve on the emptying of the microtask queue at the end of this run of
-// the event loop.
-
-async function isOperationsChainEmpty(pc) {
- let p, error;
- const signalingState = pc.signalingState;
- if (signalingState == "have-remote-offer") {
- p = pc.createOffer();
- } else {
- p = pc.createAnswer();
- }
- const state = await promiseStateFinal(p);
- try {
- await p;
- // This helper tries to avoid side-effects by always failing,
- // but createAnswer above may succeed if chained after an SRD
- // that changes the signaling state on us. Ignore that success.
- if (signalingState == pc.signalingState) {
- assert_unreached("Control. Must not succeed");
- }
- } catch (e) {
- assert_equals(e.name, "InvalidStateError",
- "isOperationsChainEmpty is working");
- }
- return state == "rejected";
-}
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const p = pc.createOffer();
- assert_false(await isOperationsChainEmpty(pc), "Non-empty chain");
- await p;
-}, "createOffer uses operations chain");
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- pc1.addTransceiver("video");
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- const candidates = [];
- for (let c; (c = (await new Promise(r => pc1.onicecandidate = r)).candidate);) {
- candidates.push(c);
- }
- pc2.addTransceiver("video");
- let fired = false;
- const p = new Promise(r => pc2.onnegotiationneeded = () => r(fired = true));
- await Promise.all([
- pc2.setRemoteDescription(offer),
- ...candidates.map(candidate => pc2.addIceCandidate(candidate)),
- pc2.setLocalDescription()
- ]);
- assert_false(fired, "Negotiationneeded mustn't have fired yet.");
- await new Promise(r => t.step_timeout(r, 0));
- assert_true(fired, "Negotiationneeded must have fired by now.");
- await p;
-}, "Negotiationneeded only fires once operations chain is empty");
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const offer = await pc.createOffer();
- pc.addTransceiver("video");
- await new Promise(r => pc.onnegotiationneeded = r);
- const p = (async () => {
- await pc.setLocalDescription();
- })();
- await new Promise(r => t.step_timeout(r, 0));
- await pc.setRemoteDescription(offer);
- await p;
-}, "Operations queue not vulnerable to recursion by chained negotiationneeded");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.removeTrack</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateAnswer
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
- partial interface RTCPeerConnection {
- ...
- void removeTrack(RTCRtpSender sender);
- RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
- optional RTCRtpTransceiverInit init);
- };
- */
-
- // Before calling removeTrack can be tested, one needs to add MediaStreamTracks to
- // a peer connection. There are two ways for adding MediaStreamTrack: addTrack and
- // addTransceiver. addTransceiver is a newer API while addTrack has been implemented
- // in current browsers for some time. As a result some of the removeTrack tests have
- // two versions so that removeTrack can be partially tested without addTransceiver
- // and the transceiver APIs being implemented.
-
- /*
- 5.1. removeTrack
- 3. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- pc.close();
- assert_throws_dom('InvalidStateError', () => pc.removeTrack(sender));
- }, 'addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- pc.close();
- assert_throws_dom('InvalidStateError', () => pc.removeTrack(sender));
- }, 'addTrack - Calling removeTrack when connection is closed should throw InvalidStateError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- const pc2 = new RTCPeerConnection();
- pc2.close();
- assert_throws_dom('InvalidStateError', () => pc2.removeTrack(sender));
- }, 'addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- const pc2 = new RTCPeerConnection();
- pc2.close();
- assert_throws_dom('InvalidStateError', () => pc2.removeTrack(sender));
- }, 'addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError');
-
- /*
- 5.1. removeTrack
- 4. If sender was not created by connection, throw an InvalidAccessError.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- assert_throws_dom('InvalidAccessError', () => pc2.removeTrack(sender));
- }, 'addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- assert_throws_dom('InvalidAccessError', () => pc2.removeTrack(sender));
- }, 'addTrack - Calling removeTrack on different connection should throw InvalidAccessError')
-
- /*
- 5.1. removeTrack
- 7. Set sender.track to null.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'sendrecv');
- assert_equals(transceiver.currentDirection, null);
-
- pc.removeTrack(sender);
- assert_equals(sender.track, null);
- assert_equals(transceiver.direction, 'recvonly');
- }, 'addTransceiver - Calling removeTrack with valid sender should set sender.track to null');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({ audio: true });
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- assert_equals(sender.track, track);
-
- pc.removeTrack(sender);
- assert_equals(sender.track, null);
- }, 'addTrack - Calling removeTrack with valid sender should set sender.track to null');
-
- /*
- 5.1. removeTrack
- 7. Set sender.track to null.
- 10. If transceiver.currentDirection is sendrecv set transceiver.direction
- to recvonly.
- */
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = caller.addTransceiver(track);
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'sendrecv');
- assert_equals(transceiver.currentDirection, null);
-
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- callee.addTrack(track, stream);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'sendrecv');
-
- caller.removeTrack(sender);
- assert_equals(sender.track, null);
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, 'sendrecv',
- 'Expect currentDirection to not change');
- }, 'Calling removeTrack with currentDirection sendrecv should set direction to recvonly');
-
- /*
- 5.1. removeTrack
- 7. Set sender.track to null.
- 11. If transceiver.currentDirection is sendonly set transceiver.direction
- to inactive.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track, { direction: 'sendonly' });
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'sendonly');
- assert_equals(transceiver.currentDirection, null);
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'sendonly');
-
- pc.removeTrack(sender);
- assert_equals(sender.track, null);
- assert_equals(transceiver.direction, 'inactive');
- assert_equals(transceiver.currentDirection, 'sendonly',
- 'Expect currentDirection to not change');
- }, 'Calling removeTrack with currentDirection sendonly should set direction to inactive');
-
- /*
- 5.1. removeTrack
- 7. Set sender.track to null.
- 9. If transceiver.currentDirection is recvonly or inactive,
- then abort these steps.
- */
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = caller.addTransceiver(track, { direction: 'recvonly' });
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, null);
-
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- callee.addTrack(track, stream);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'recvonly');
-
- caller.removeTrack(sender);
- assert_equals(sender.track, null);
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, 'recvonly');
- }, 'Calling removeTrack with currentDirection recvonly should not change direction');
-
- /*
- 5.1. removeTrack
- 7. Set sender.track to null.
- 9. If transceiver.currentDirection is recvonly or inactive,
- then abort these steps.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const transceiver = pc.addTransceiver(track, { direction: 'inactive' });
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
- assert_equals(transceiver.direction, 'inactive');
- assert_equals(transceiver.currentDirection, null);
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const answer = await generateAnswer(offer);
- await pc.setRemoteDescription(answer);
- assert_equals(transceiver.currentDirection, 'inactive');
-
- pc.removeTrack(sender);
- assert_equals(sender.track, null);
- assert_equals(transceiver.direction, 'inactive');
- assert_equals(transceiver.currentDirection, 'inactive');
- }, 'Calling removeTrack with currentDirection inactive should not change direction');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- pc.getTransceivers()[0].stop();
- pc.removeTrack(sender);
- assert_equals(sender.track, track);
- }, "Calling removeTrack on a stopped transceiver should be a no-op");
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = pc.addTrack(track, stream);
-
- await sender.replaceTrack(null);
- pc.removeTrack(sender);
- assert_equals(sender.track, null);
-}, "Calling removeTrack on a null track should have no effect");
-
-
- /*
- TODO
- 5.1. removeTrack
- Stops sending media from sender. The RTCRtpSender will still appear
- in getSenders. Doing so will cause future calls to createOffer to
- mark the media description for the corresponding transceiver as
- recvonly or inactive, as defined in [JSEP] (section 5.2.2.).
-
- When the other peer stops sending a track in this manner, an ended
- event is fired at the MediaStreamTrack object.
-
- 6. If sender is not in senders (which indicates that it was removed
- due to setting an RTCSessionDescription of type "rollback"),
- then abort these steps.
- 12. Update the negotiation-needed flag for connection.
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-"use strict";
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
-
- await pc1.setLocalDescription(await pc1.createOffer());
- pc1.restartIce();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
- // When the setRemoteDescription() promise above is resolved a task should be
- // queued to fire the onnegotiationneeded event. Because of this, we should
- // have time to hook up the event listener *after* awaiting the SRD promise.
- await new Promise(r => pc1.onnegotiationneeded = r);
-}, "Negotiation needed when returning to stable does not fire too early");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-"use strict";
-
-function getLines(sdp, startsWith) {
- const lines = sdp.split("\r\n").filter(l => l.startsWith(startsWith));
- assert_true(lines.length > 0, `One or more ${startsWith} in sdp`);
- return lines;
-}
-
-const getUfrags = ({sdp}) => getLines(sdp, "a=ice-ufrag:");
-const getPwds = ({sdp}) => getLines(sdp, "a=ice-pwd:");
-
-const negotiators = [
- {
- tag: "",
- async setOffer(pc) {
- await pc.setLocalDescription(await pc.createOffer());
- },
- async setAnswer(pc) {
- await pc.setLocalDescription(await pc.createAnswer());
- },
- },
- {
- tag: " (perfect negotiation)",
- async setOffer(pc) {
- await pc.setLocalDescription();
- },
- async setAnswer(pc) {
- await pc.setLocalDescription();
- },
- },
-];
-
-async function exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator) {
- await negotiator.setOffer(pc1);
- await pc2.setRemoteDescription(pc1.localDescription);
- await negotiator.setAnswer(pc2);
- await pc1.setRemoteDescription(pc2.localDescription); // End on pc1. No race
-}
-
-async function exchangeOfferAnswerEndOnSecond(pc1, pc2, negotiator) {
- await negotiator.setOffer(pc1);
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc1.setRemoteDescription(await pc2.createAnswer());
- await pc2.setLocalDescription(pc1.remoteDescription); // End on pc2. No race
-}
-
-async function assertNoNegotiationNeeded(t, pc, state = "stable") {
- assert_equals(pc.signalingState, state, `In ${state} state`);
- const event = await Promise.race([
- new Promise(r => pc.onnegotiationneeded = r),
- new Promise(r => t.step_timeout(r, 10))
- ]);
- assert_equals(event, undefined, "No negotiationneeded event");
-}
-
-// In Chromium, assert_equals() produces test expectations with the values
-// compared. Because ufrags are different on each run, this would make Chromium
-// test expectations different on each run on tests that failed when comparing
-// ufrags. To work around this problem, assert_ufrags_equals() and
-// assert_ufrags_not_equals() should be preferred over assert_equals() and
-// assert_not_equals().
-function assert_ufrags_equals(x, y, description) {
- assert_true(x === y, description);
-}
-function assert_ufrags_not_equals(x, y, description) {
- assert_false(x === y, description);
-}
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- pc.close();
- pc.restartIce();
- await assertNoNegotiationNeeded(t, pc, "closed");
-}, "restartIce() has no effect on a closed peer connection");
-
-// Run remaining tests twice: once for each negotiator
-
-for (const negotiator of negotiators) {
- const {tag} = negotiator;
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- pc1.restartIce();
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() has no effect on initial negotiation${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- pc1.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- }, `restartIce() fires negotiationneeded after initial negotiation${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2");
-
- pc1.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
-
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
- }, `restartIce() causes fresh ufrags${tag}`);
-
- promise_test(async t => {
- const config = {bundlePolicy: "max-bundle"};
- const pc1 = new RTCPeerConnection(config);
- const pc2 = new RTCPeerConnection(config);
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
- pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
-
- // See the explanation below about Chrome's onnegotiationneeded firing
- // too early.
- const negotiationNeededPromise1 =
- new Promise(r => pc1.onnegotiationneeded = r);
- pc1.addTransceiver("video");
- pc1.addTransceiver("audio");
- await negotiationNeededPromise1;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [videoTc, audioTc] = pc1.getTransceivers();
- const [videoTp, audioTp] =
- pc1.getTransceivers().map(tc => tc.sender.transport);
- assert_equals(pc1.getTransceivers().length, 2, 'transceiver count');
-
- // On Chrome, it is possible (likely, even) that videoTc.sender.transport.state
- // will be 'connected' by the time we get here. We'll race 2 promises here:
- // 1. Resolve after onstatechange is called with connected state.
- // 2. If already connected, resolve immediately.
- await Promise.race([
- new Promise(r => videoTc.sender.transport.onstatechange =
- () => videoTc.sender.transport.state == "connected" && r()),
- new Promise(r => videoTc.sender.transport.state == "connected" && r())
- ]);
- assert_equals(videoTc.sender.transport.state, "connected");
-
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- assert_equals(videoTp, pc1.getTransceivers()[0].sender.transport,
- 'offer/answer retains dtls transport');
- assert_equals(audioTp, pc1.getTransceivers()[1].sender.transport,
- 'offer/answer retains dtls transport');
-
- const negotiationNeededPromise2 =
- new Promise(r => pc1.onnegotiationneeded = r);
- pc1.restartIce();
- await negotiationNeededPromise2;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [newVideoTp, newAudioTp] =
- pc1.getTransceivers().map(tc => tc.sender.transport);
- assert_equals(videoTp, newVideoTp, 'ice restart retains dtls transport');
- assert_equals(audioTp, newAudioTp, 'ice restart retains dtls transport');
- }, `restartIce() retains dtls transports${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- await negotiator.setOffer(pc1);
- pc1.restartIce();
- await pc2.setRemoteDescription(pc1.localDescription);
- await negotiator.setAnswer(pc2);
- // Several tests in this file initializes the onnegotiationneeded listener
- // before the setLocalDescription() or setRemoteDescription() that we expect
- // to trigger negotiation needed. This allows Chrome to exercise these tests
- // without timing out due to a bug that causes onnegotiationneeded to fire too
- // early.
- // TODO(https://crbug.com/985797): Once Chrome does not fire ONN too early,
- // simply do "await new Promise(...)" instead of
- // "await negotiationNeededPromise" here and in other tests in this file.
- const negotiationNeededPromise =
- new Promise(r => pc1.onnegotiationneeded = r);
- await pc1.setRemoteDescription(pc2.localDescription);
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
- await negotiationNeededPromise;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() works in have-local-offer${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await negotiator.setOffer(pc1);
- pc1.restartIce();
- await pc2.setRemoteDescription(pc1.localDescription);
- await negotiator.setAnswer(pc2);
- const negotiationNeededPromise =
- new Promise(r => pc1.onnegotiationneeded = r);
- await pc1.setRemoteDescription(pc2.localDescription);
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
- await negotiationNeededPromise;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() works in initial have-local-offer${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- await negotiator.setOffer(pc2);
- await pc1.setRemoteDescription(pc2.localDescription);
- pc1.restartIce();
- await pc2.setRemoteDescription(await pc1.createAnswer());
- const negotiationNeededPromise =
- new Promise(r => pc1.onnegotiationneeded = r);
- await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
- await negotiationNeededPromise;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() works in have-remote-offer${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc2.addTransceiver("audio");
- await negotiator.setOffer(pc2);
- await pc1.setRemoteDescription(pc2.localDescription);
- pc1.restartIce();
- await pc2.setRemoteDescription(await pc1.createAnswer());
- await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() does nothing in initial have-remote-offer${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- pc1.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- const negotiationNeededPromise =
- new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnSecond(pc2, pc1, negotiator);
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2");
- await negotiationNeededPromise;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() survives remote offer${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- pc1.restartIce();
- pc2.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnSecond(pc2, pc1, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
-
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
- assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() is satisfied by remote ICE restart${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- pc1.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- await pc1.setLocalDescription(await pc1.createOffer({iceRestart: false}));
- await pc2.setRemoteDescription(pc1.localDescription);
- await negotiator.setAnswer(pc2);
- await pc1.setRemoteDescription(pc2.localDescription);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() trumps {iceRestart: false}${tag}`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- await new Promise(r => pc1.onnegotiationneeded = r);
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
-
- const [oldUfrag1] = getUfrags(pc1.localDescription);
- const [oldUfrag2] = getUfrags(pc2.localDescription);
-
- pc1.restartIce();
- await new Promise(r => pc1.onnegotiationneeded = r);
- await negotiator.setOffer(pc1);
- const negotiationNeededPromise =
- new Promise(r => pc1.onnegotiationneeded = r);
- await pc1.setLocalDescription({type: "rollback"});
- await negotiationNeededPromise;
- await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
- const [newUfrag1] = getUfrags(pc1.localDescription);
- const [newUfrag2] = getUfrags(pc2.localDescription);
- assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
- assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
- await assertNoNegotiationNeeded(t, pc1);
- }, `restartIce() survives rollback${tag}`);
-
-}
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Set Session Description - Transceiver Tests</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateAnswer
-
- /*
- 4.3.2. Interface Definition
-
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setLocalDescription(
- RTCSessionDescriptionInit description);
-
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
-
- 5.4. RTCRtpTransceiver Interface
-
- interface RTCRtpTransceiver {
- readonly attribute DOMString? mid;
- [SameObject]
- readonly attribute RTCRtpSender sender;
- [SameObject]
- readonly attribute RTCRtpReceiver receiver;
- readonly attribute RTCRtpTransceiverDirection direction;
- readonly attribute RTCRtpTransceiverDirection? currentDirection;
- ...
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 7. If description is set as a local description, then run the following steps for
- each media description in description that is not yet associated with an
- RTCRtpTransceiver object:
- 1. Let transceiver be the RTCRtpTransceiver used to create the media
- description.
- 2. Set transceiver's mid value to the mid of the corresponding media
- description.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.mid, null);
-
- return pc.createOffer()
- .then(offer => {
- assert_equals(transceiver.mid, null,
- 'Expect transceiver.mid to still be null after createOffer');
-
- return pc.setLocalDescription(offer)
- .then(() => {
- assert_equals(typeof transceiver.mid, 'string',
- 'Expect transceiver.mid to set to valid string value');
-
- assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver.mid}`), true,
- 'Expect transceiver mid to be found in offer SDP');
- });
- });
- }, 'setLocalDescription(offer) with m= section should assign mid to corresponding transceiver');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 8. If description is set as a remote description, then run the following steps
- for each media description in description:
- 2. If no suitable transceiver is found (transceiver is unset), run the following
- steps:
- 1. Create an RTCRtpSender, sender, from the media description.
- 2. Create an RTCRtpReceiver, receiver, from the media description.
- 3. Create an RTCRtpTransceiver with sender, receiver and direction, and let
- transceiver be the result.
- 3. Set transceiver's mid value to the mid of the corresponding media description.
- */
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- const transceiver1 = pc1.addTransceiver('audio');
- assert_array_equals(pc1.getTransceivers(), [transceiver1]);
- assert_array_equals(pc2.getTransceivers(), []);
-
- return pc1.createOffer()
- .then(offer => {
- return Promise.all([
- pc1.setLocalDescription(offer),
- pc2.setRemoteDescription(offer)
- ])
- .then(() => {
- const transceivers = pc2.getTransceivers();
- assert_equals(transceivers.length, 1,
- 'Expect new transceiver added to pc2 after setRemoteDescription');
-
- const [ transceiver2 ] = transceivers;
-
- assert_equals(typeof transceiver2.mid, 'string',
- 'Expect transceiver2.mid to be set');
-
- assert_equals(transceiver1.mid, transceiver2.mid,
- 'Expect transceivers of both side to have the same mid');
-
- assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver2.mid}`), true,
- 'Expect transceiver mid to be found in offer SDP');
- });
- });
- }, 'setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 9. If description is of type "rollback", then run the following steps:
- 1. If the mid value of an RTCRtpTransceiver was set to a non-null value by
- the RTCSessionDescription that is being rolled back, set the mid value
- of that transceiver to null, as described by [JSEP] (section 4.1.8.2.).
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.mid, null);
-
- return pc.createOffer()
- .then(offer => {
- assert_equals(transceiver.mid, null);
- return pc.setLocalDescription(offer);
- })
- .then(() => {
- assert_not_equals(transceiver.mid, null);
- return pc.setLocalDescription({ type: 'rollback' });
- })
- .then(() => {
- assert_equals(transceiver.mid, null,
- 'Expect transceiver.mid to become null again after rollback');
- });
- }, 'setLocalDescription(rollback) should unset transceiver.mid');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver1 = pc.addTransceiver('audio');
- assert_equals(transceiver1.mid, null);
-
- return pc.createOffer()
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer)))
- .then(answer => pc.setRemoteDescription(answer))
- .then(() => {
- // pc is back to stable state
- // create another transceiver
- const transceiver2 = pc.addTransceiver('video');
-
- assert_not_equals(transceiver1.mid, null);
- assert_equals(transceiver2.mid, null);
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => {
- assert_not_equals(transceiver1.mid, null);
- assert_not_equals(transceiver2.mid, null,
- 'Expect transceiver2.mid to become set');
-
- return pc.setLocalDescription({ type: 'rollback' });
- })
- .then(() => {
- assert_not_equals(transceiver1.mid, null,
- 'Expect transceiver1.mid to stay set');
-
- assert_equals(transceiver2.mid, null,
- 'Expect transceiver2.mid to be rolled back to null');
- });
- })
- }, 'setLocalDescription(rollback) should only unset transceiver mids associated with current round');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 9. If description is of type "rollback", then run the following steps:
- 2. If an RTCRtpTransceiver was created by applying the RTCSessionDescription
- that is being rolled back, and a track has not been attached to it via
- addTrack, remove that transceiver from connection's set of transceivers,
- as described by [JSEP] (section 4.1.8.2.).
- */
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio');
-
- return pc1.createOffer()
- .then(offer => pc2.setRemoteDescription(offer))
- .then(() => {
- const transceivers = pc2.getTransceivers();
- assert_equals(transceivers.length, 1);
- const [ transceiver ] = transceivers;
-
- assert_equals(typeof transceiver.mid, 'string',
- 'Expect transceiver.mid to be set');
-
- return pc2.setRemoteDescription({ type: 'rollback' })
- .then(() => {
- assert_equals(transceiver.mid, null,
- 'Expect transceiver.mid to be unset');
-
- assert_array_equals(pc2.getTransceivers(), [],
- `Expect transceiver to be removed from pc2's transceiver list`);
- });
- });
- }, 'setRemoteDescription(rollback) should remove newly created transceiver from transceiver list');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio');
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
-
- await pc2.setRemoteDescription(offer);
- pc2.getTransceivers()[0].stop();
- const answer = await pc2.createAnswer();
-
- await pc1.setRemoteDescription(answer);
-
- assert_equals(pc1.getTransceivers()[0].currentDirection, 'inactive', 'A stopped m-line should give an inactive transceiver');
- }, 'setRemoteDescription should set transceiver inactive if its corresponding m section is rejected');
-
- /*
- TODO
- - Steps for transceiver direction is added to tip of tree draft, but not yet
- published as editor's draft
-
- 4.3.1.6. Set the RTCSessionSessionDescription
- 8. If description is set as a remote description, then run the following steps
- for each media description in description:
- 1. As described by [JSEP] (section 5.9.), attempt to find an existing
- RTCRtpTransceiver object, transceiver, to represent the media description.
- 3. 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. If the media description is rejected, and transceiver is not already stopped,
- stop the RTCRtpTransceiver transceiver.
-
- [JSEP]
- 5.9. Applying a Remote Description
- - If the m= section is not associated with any RtpTransceiver
- (possibly because it was dissociated in the previous step),
- either find an RtpTransceiver or create one according to the
- following steps:
-
- - If the m= section is sendrecv or recvonly, and there are
- RtpTransceivers of the same type that were added to the
- PeerConnection by addTrack and are not associated with any
- m= section and are not stopped, find the first (according to
- the canonical order described in Section 5.2.1) such
- RtpTransceiver.
-
- - If no RtpTransceiver was found in the previous step, create
- one with a recvonly direction.
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setLocalDescription</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateAnswer
- // assert_session_desc_similar
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.2. If description is set as a local description, then run one of the following
- steps:
-
- - If description is of type "answer", then this completes an offer answer
- negotiation.
-
- Set connection's currentLocalDescription to description and
- currentRemoteDescription to the value of pendingRemoteDescription.
-
- Set both pendingRemoteDescription and pendingLocalDescription to null.
-
- Finally set connection's signaling state to stable.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer())
- .then(answer =>
- pc.setLocalDescription(answer)
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
- assert_session_desc_similar(pc.localDescription, answer);
- assert_session_desc_similar(pc.remoteDescription, offer);
-
- assert_session_desc_similar(pc.currentLocalDescription, answer);
- assert_session_desc_similar(pc.currentRemoteDescription, offer);
-
- assert_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.pendingRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer', 'stable']);
- })));
- }, 'setLocalDescription() with valid answer should succeed');
-
- /*
- 4.3.2. setLocalDescription
- 3. Let lastAnswer be the result returned by the last call to createAnswer.
- 4. If description.sdp is null and description.type is answer, set description.sdp
- to lastAnswer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer())
- .then(answer =>
- pc.setLocalDescription({ type: 'answer' })
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
- assert_session_desc_similar(pc.localDescription, answer);
- assert_session_desc_similar(pc.remoteDescription, offer);
-
- assert_session_desc_similar(pc.currentLocalDescription, answer);
- assert_session_desc_similar(pc.currentRemoteDescription, offer);
-
- assert_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.pendingRemoteDescription, null);
- })));
- }, 'setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer');
-
- /*
- 4.3.2. setLocalDescription
- 3. Let lastAnswer be the result returned by the last call to createAnswer.
- 7. If description.type is answer and description.sdp does not match lastAnswer,
- reject the promise with a newly created InvalidModificationError and abort these
- steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => generateAnswer(offer))
- .then(answer => pc.setLocalDescription(answer))
- .then(() => t.unreached_func("setLocalDescription should have rejected"),
- (error) => assert_equals(error.name, 'InvalidModificationError')));
- }, 'setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps.
-
- [jsep]
- 5.5. If the type is "pranswer" or "answer", the PeerConnection
- state MUST be either "have-remote-offer" or "have-local-pranswer".
- */
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer(); // [[LastAnswer]] slot set
- await pc2.setRemoteDescription({type: "rollback"});
- pc2.addTransceiver('video', { direction: 'recvonly' });
- await pc2.createOffer(); // [[LastOffer]] slot set
- await pc2.setRemoteDescription(offer);
- await pc2.setLocalDescription(answer); // Should check against [[LastAnswer]], not [[LastOffer]]
- }, "Setting previously generated answer after a call to createOffer should work");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await pc2.setRemoteDescription(await pc1.createOffer());
- const answer = await pc2.createAnswer();
- const sldPromise = pc2.setLocalDescription(answer);
-
- assert_equals(pc2.signalingState, "have-remote-offer", "signalingState should not be set synchronously after a call to sLD");
-
- assert_equals(pc2.pendingLocalDescription, null, "pendingLocalDescription should never be set due to sLD(answer)");
- assert_not_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should not be set synchronously after a call to sLD");
- assert_equals(pc2.pendingRemoteDescription.type, "offer");
- assert_equals(pc2.remoteDescription.sdp, pc2.pendingRemoteDescription.sdp);
- assert_equals(pc2.currentLocalDescription, null, "currentLocalDescription should not be set synchronously after a call to sLD");
- assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sLD");
-
- const stablePromise = new Promise(resolve => {
- pc2.onsignalingstatechange = () => {
- resolve(pc2.signalingState);
- }
- });
- const raceValue = await Promise.race([stablePromise, sldPromise]);
- assert_equals(raceValue, "stable", "signalingstatechange event should fire before sLD resolves");
- assert_equals(pc2.pendingLocalDescription, null, "pendingLocalDescription should never be set due to sLD(answer)");
- assert_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should be updated before the signalingstatechange event");
- assert_not_equals(pc2.currentLocalDescription, null, "currentLocalDescription should be updated before the signalingstatechange event");
- assert_equals(pc2.currentLocalDescription.type, "answer");
- assert_equals(pc2.currentLocalDescription.sdp, pc2.localDescription.sdp);
- assert_not_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should be updated before the signalingstatechange event");
- assert_equals(pc2.currentRemoteDescription.type, "offer");
- assert_equals(pc2.currentRemoteDescription.sdp, pc2.remoteDescription.sdp);
-
- await sldPromise;
- }, "setLocalDescription(answer) should update internal state with a queued task, in the right order");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setLocalDescription</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateDataChannelOffer
- // assert_session_desc_not_similar
- // assert_session_desc_similar
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.2. setLocalDescription
- 2. Let lastOffer be the result returned by the last call to createOffer.
- 5. If description.sdp is null and description.type is offer, set description.sdp
- to lastOffer.
-
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.2. If description is set as a local description, then run one of the following
- steps:
- - If description is of type "offer", set connection.pendingLocalDescription
- to description and signaling state to have-local-offer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.pendingLocalDescription, offer);
- assert_equals(pc.currentLocalDescription, null);
-
- assert_array_equals(states, ['have-local-offer']);
- }));
- }, 'setLocalDescription with valid offer should succeed');
-
- /*
- 4.3.2. setLocalDescription
- 2. Let lastOffer be the result returned by the last call to createOffer.
- 5. If description.sdp is null and description.type is offer, set description.sdp
- to lastOffer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription({ type: 'offer' })
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.pendingLocalDescription, offer);
- assert_equals(pc.currentLocalDescription, null);
- }));
- }, 'setLocalDescription with type offer and null sdp should use lastOffer generated from createOffer');
-
- /*
- 4.3.2. setLocalDescription
- 2. Let lastOffer be the result returned by the last call to createOffer.
- 6. If description.type is offer and description.sdp does not match lastOffer,
- reject the promise with a newly created InvalidModificationError and abort
- these steps.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- return generateDataChannelOffer(pc)
- .then(offer => pc2.setLocalDescription(offer))
- .then(() => t.unreached_func("setLocalDescription should have rejected"),
- (error) => assert_equals(error.name, 'InvalidModificationError'));
- }, 'setLocalDescription() with offer not created by own createOffer() should reject with InvalidModificationError');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer1 =>
- pc.setLocalDescription(offer1)
- .then(() =>
- generateVideoReceiveOnlyOffer(pc)
- .then(offer2 =>
- pc.setLocalDescription(offer2)
- .then(() => {
- assert_session_desc_not_similar(offer1, offer2);
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_session_desc_similar(pc.localDescription, offer2);
- assert_session_desc_similar(pc.pendingLocalDescription, offer2);
- assert_equals(pc.currentLocalDescription, null);
-
- assert_array_equals(states, ['have-local-offer']);
- }))));
- }, 'Creating and setting offer multiple times should succeed');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const offer = await pc1.createOffer(); // [[LastOffer]] set
- pc2.addTransceiver('video', { direction: 'recvonly' });
- const offer2 = await pc2.createOffer();
- await pc1.setRemoteDescription(offer2);
- await pc1.createAnswer(); // [[LastAnswer]] set
- await pc1.setRemoteDescription({type: "rollback"});
- await pc1.setLocalDescription(offer);
- }, "Setting previously generated offer after a call to createAnswer should work");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- await pc1.setLocalDescription(await pc1.createOffer());
-
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- assert_equals(pc1.getTransceivers().length, 1);
- assert_equals(pc1.getTransceivers()[0].receiver.track.kind, "audio");
- assert_equals(pc2.getTransceivers().length, 1);
- assert_equals(pc2.getTransceivers()[0].receiver.track.kind, "audio");
- }, "Negotiation works when there has been a repeated setLocalDescription(offer)");
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio', { direction: 'recvonly' });
- const sldPromise = pc.setLocalDescription(await pc.createOffer());
-
- assert_equals(pc.signalingState, "stable", "signalingState should not be set synchronously after a call to sLD");
-
- assert_equals(pc.pendingLocalDescription, null, "pendingRemoteDescription should never be set due to sLD");
- assert_equals(pc.pendingRemoteDescription, null, "pendingLocalDescription should not be set synchronously after a call to sLD");
- assert_equals(pc.currentLocalDescription, null, "currentLocalDescription should not be set synchronously after a call to sLD");
- assert_equals(pc.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sLD");
-
- const statePromise = new Promise(resolve => {
- pc.onsignalingstatechange = () => {
- resolve(pc.signalingState);
- }
- });
- const raceValue = await Promise.race([statePromise, sldPromise]);
- assert_equals(raceValue, "have-local-offer", "signalingstatechange event should fire before sLD resolves");
- assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD");
- assert_not_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should be updated before the signalingstatechange event");
- assert_equals(pc.pendingLocalDescription.type, "offer");
- assert_equals(pc.pendingLocalDescription.sdp, pc.localDescription.sdp);
- assert_equals(pc.currentLocalDescription, null, "currentLocalDescription should never be updated due to sLD(offer)");
- assert_equals(pc.currentRemoteDescription, null, "currentRemoteDescription should never be updated due to sLD(offer)");
-
- await sldPromise;
- }, "setLocalDescription(offer) should update internal state with a queued task, in the right order");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-"use strict";
-
-const kSmallTimeoutMs = 100;
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
-
- const signalingStateChangeEvent
- = new EventWatcher(t, offerer, 'signalingstatechange')
- .wait_for('signalingstatechange');
- await offerer.setLocalDescription();
- await signalingStateChangeEvent;
- assert_equals(offerer.signalingState, 'have-local-offer');
-}, "Parameterless SLD() in 'stable' goes to 'have-local-offer'");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
-
- await offerer.setLocalDescription();
- assert_not_equals(offerer.pendingLocalDescription, null);
-}, "Parameterless SLD() in 'stable' sets pendingLocalDescription");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
-
- const transceiver = offerer.addTransceiver('audio');
- assert_equals(transceiver.mid, null);
- await offerer.setLocalDescription();
- assert_not_equals(transceiver.mid, null);
-}, "Parameterless SLD() in 'stable' assigns transceiver.mid");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
- const answerer = new RTCPeerConnection();
- t.add_cleanup(() => answerer.close());
-
- await answerer.setRemoteDescription(await offerer.createOffer());
- const signalingStateChangeEvent
- = new EventWatcher(t, answerer, 'signalingstatechange')
- .wait_for('signalingstatechange');
- await answerer.setLocalDescription();
- await signalingStateChangeEvent;
- assert_equals(answerer.signalingState, 'stable');
-}, "Parameterless SLD() in 'have-remote-offer' goes to 'stable'");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
- const answerer = new RTCPeerConnection();
- t.add_cleanup(() => answerer.close());
-
- await answerer.setRemoteDescription(await offerer.createOffer());
- await answerer.setLocalDescription();
- assert_not_equals(answerer.currentLocalDescription, null);
-}, "Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
- const answerer = new RTCPeerConnection();
- t.add_cleanup(() => answerer.close());
-
- offerer.addTransceiver('audio');
- const onTransceiverPromise = new Promise(resolve =>
- answerer.ontrack = e => resolve(e.transceiver));
- await answerer.setRemoteDescription(await offerer.createOffer());
- const transceiver = await onTransceiverPromise;
- await answerer.setLocalDescription();
- assert_equals(transceiver.currentDirection, 'recvonly');
-}, "Parameterless SLD() in 'have-remote-offer' sets " +
- "transceiver.currentDirection");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- offerer.close();
- try {
- await offerer.setLocalDescription();
- assert_not_reached();
- } catch (e) {
- assert_equals(e.name, "InvalidStateError");
- }
-}, "Parameterless SLD() rejects with InvalidStateError if already closed");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
-
- const p = Promise.race([
- offerer.setLocalDescription(),
- new Promise(r => t.step_timeout(() => r("timeout"), kSmallTimeoutMs))
- ]);
- offerer.close();
- assert_equals(await p, "timeout");
-}, "Parameterless SLD() never settles if closed while pending");
-
-promise_test(async t => {
- const offerer = new RTCPeerConnection();
- t.add_cleanup(() => offerer.close());
- const answerer = new RTCPeerConnection();
- t.add_cleanup(() => answerer.close());
-
- // Implicitly create an offer.
- await offerer.setLocalDescription();
- await answerer.setRemoteDescription(offerer.pendingLocalDescription);
- // Implicitly create an answer.
- await answerer.setLocalDescription();
- await offerer.setRemoteDescription(answerer.currentLocalDescription);
-}, "Parameterless SLD() in a full O/A exchange succeeds");
-
-promise_test(async t => {
- const answerer = new RTCPeerConnection();
- try {
- await answerer.setRemoteDescription();
- assert_not_reached();
- } catch (e) {
- assert_equals(e.name, "TypeError");
- }
-}, "Parameterless SRD() rejects with TypeError.");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setLocalDescription pranswer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // assert_session_desc_similar
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setLocalDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? localDescription;
- readonly attribute RTCSessionDescription? currentLocalDescription;
- readonly attribute RTCSessionDescription? pendingLocalDescription;
-
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps.
-
- [jsep]
- 5.5. If the type is "pranswer" or "answer", the PeerConnection
- state MUST be either "have-remote-offer" or "have-local-pranswer".
- */
-
- /*
- 4.3.1.6 Set the RTCSessionSessionDescription
- 2.2.2. If description is set as a local description, then run one of the
- following steps:
- - If description is of type "pranswer", then set
- connection.pendingLocalDescription to description and signaling state to
- have-local-pranswer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer())
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setLocalDescription(pranswer)
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-pranswer');
-
- assert_session_desc_similar(pc.remoteDescription, offer);
- assert_session_desc_similar(pc.pendingRemoteDescription, offer);
- assert_equals(pc.currentRemoteDescription, null);
-
- assert_session_desc_similar(pc.localDescription, pranswer);
- assert_session_desc_similar(pc.pendingLocalDescription, pranswer);
- assert_equals(pc.currentLocalDescription, null);
-
-
- assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer']);
- });
- }));
- }, 'setLocalDescription(pranswer) should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer())
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setLocalDescription(pranswer)
- .then(() => pc.setLocalDescription(pranswer))
- .then(() => {
- assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer']);
- });
- }));
- }, 'setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer())
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setLocalDescription(pranswer)
- .then(() => pc.setLocalDescription(answer))
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
- assert_session_desc_similar(pc.localDescription, answer);
- assert_session_desc_similar(pc.remoteDescription, offer);
-
- assert_session_desc_similar(pc.currentLocalDescription, answer);
- assert_session_desc_similar(pc.currentRemoteDescription, offer);
-
- assert_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.pendingRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer', 'stable']);
- });
- }));
- }, 'setLocalDescription(answer) from have-local-pranswer state should succeed');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setLocalDescription rollback</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // assert_session_desc_similar
- // generateAudioReceiveOnlyOffer
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setLocalDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? localDescription;
- readonly attribute RTCSessionDescription? currentLocalDescription;
- readonly attribute RTCSessionDescription? pendingLocalDescription;
-
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.2. If description is set as a local description, then run one of the
- following steps:
- - If description is of type "rollback", then this is a rollback. Set
- connection.pendingLocalDescription to null and signaling state to stable.
- */
- promise_test(t=> {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_not_equals(pc.localDescription, null);
- assert_not_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.currentLocalDescription, null);
-
- return pc.setLocalDescription({ type: 'rollback' });
- })
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
- assert_equals(pc.localDescription, null);
- assert_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.currentLocalDescription, null);
-
- assert_array_equals(states, ['have-local-offer', 'stable']);
- });
- }, 'setLocalDescription(rollback) from have-local-offer state should reset back to stable state');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps. Note that this implies that once the answerer has performed
- setLocalDescription with his answer, this cannot be rolled back.
-
- [jsep]
- 4.1.8.2. Rollback
- - Rollback can only be used to cancel proposed changes;
- there is no support for rolling back from a stable state to a
- previous stable state
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return promise_rejects_dom(t, 'InvalidStateError',
- pc.setLocalDescription({ type: 'rollback' }));
- }, `setLocalDescription(rollback) from stable state should reject with InvalidStateError`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => pc.createAnswer()))
- .then(answer => pc.setLocalDescription(answer))
- .then(() => {
- return promise_rejects_dom(t, 'InvalidStateError',
- pc.setLocalDescription({ type: 'rollback' }));
- });
- }, `setLocalDescription(rollback) after setting answer description should reject with InvalidStateError`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => pc.setLocalDescription({
- type: 'rollback',
- sdp: '!<Invalid SDP Content>;'
- }));
- }, `setLocalDescription(rollback) should ignore invalid sdp content and succeed`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio', { direction: 'recvonly' });
- await pc.setLocalDescription(await pc.createOffer());
- const sldPromise = pc.setLocalDescription({type: "rollback"});
-
- assert_equals(pc.signalingState, "have-local-offer", "signalingState should not be set synchronously after a call to sLD");
-
- assert_not_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should not be set synchronously after a call to sLD");
- assert_equals(pc.pendingLocalDescription.type, "offer");
- assert_equals(pc.pendingLocalDescription.sdp, pc.localDescription.sdp);
- assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD(offer)");
-
- const stablePromise = new Promise(resolve => {
- pc.onsignalingstatechange = () => {
- resolve(pc.signalingState);
- }
- });
- const raceValue = await Promise.race([stablePromise, sldPromise]);
- assert_equals(raceValue, "stable", "signalingstatechange event should fire before sLD resolves");
- assert_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should be updated before the signalingstatechange event");
- assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD(offer)");
-
- await sldPromise;
- }, "setLocalDescription(rollback) should update internal state with a queued tassk, in the right order");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setLocalDescription</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateDataChannelOffer
- // assert_session_desc_not_similar
- // assert_session_desc_similar
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer1 =>
- pc.setLocalDescription(offer1)
- .then(() => generateAnswer(offer1))
- .then(answer => pc.setRemoteDescription(answer))
- .then(() => {
- pc.createDataChannel('test');
- return generateVideoReceiveOnlyOffer(pc);
- })
- .then(offer2 =>
- pc.setLocalDescription(offer2)
- .then(() => {
- assert_equals(pc.signalingState, 'have-local-offer');
- assert_session_desc_not_similar(offer1, offer2);
- assert_session_desc_similar(pc.localDescription, offer2);
- assert_session_desc_similar(pc.currentLocalDescription, offer1);
- assert_session_desc_similar(pc.pendingLocalDescription, offer2);
-
- assert_array_equals(states, ['have-local-offer', 'stable', 'have-local-offer']);
- })));
- }, 'Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- pc1.addEventListener('signalingstatechange', () => states.push(pc1.signalingState));
-
- assert_equals(pc1.localDescription, null);
- assert_equals(pc1.currentLocalDescription, null);
- assert_equals(pc1.pendingLocalDescription, null);
-
- pc1.createDataChannel('test');
- const offer = await pc1.createOffer();
-
- assert_equals(pc1.localDescription, null);
- assert_equals(pc1.currentLocalDescription, null);
- assert_equals(pc1.pendingLocalDescription, null);
-
- await pc1.setLocalDescription(offer);
-
- assert_session_desc_similar(pc1.localDescription, offer);
- assert_equals(pc1.currentLocalDescription, null);
- assert_session_desc_similar(pc1.pendingLocalDescription, offer);
-
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- assert_equals(pc1.signalingState, 'stable');
- assert_session_desc_similar(pc1.localDescription, offer);
- assert_session_desc_similar(pc1.currentLocalDescription, offer);
- assert_equals(pc1.pendingLocalDescription, null);
-
- const stream = await getNoiseStream({audio:true});
- pc2.addTrack(stream.getTracks()[0], stream);
-
- const reoffer = await pc2.createOffer();
- await pc2.setLocalDescription(reoffer);
- await pc1.setRemoteDescription(reoffer);
- const reanswer = await pc1.createAnswer();
- await pc1.setLocalDescription(reanswer);
-
- assert_session_desc_similar(pc1.localDescription, reanswer);
- assert_session_desc_similar(pc1.currentLocalDescription, reanswer);
- assert_equals(pc1.pendingLocalDescription, null);
- }, 'Switching role from answerer to offerer after going back to stable state should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const offer = await pc.createOffer();
- let eventSequence = '';
- const signalingstatechangeResolver = new Resolver();
- pc.onsignalingstatechange = () => {
- eventSequence += 'onsignalingstatechange;';
- signalingstatechangeResolver.resolve();
- };
- await pc.setLocalDescription(offer);
- eventSequence += 'setLocalDescription;';
- await signalingstatechangeResolver;
- assert_equals(eventSequence, 'onsignalingstatechange;setLocalDescription;');
- }, 'onsignalingstatechange fires before setLocalDescription resolves');
-
- /*
- TODO
- 4.3.2. setLocalDescription
- 4. If description.sdp is null and description.type is pranswer, set description.sdp
- to lastAnswer.
- 7. If description.type is pranswer and description.sdp does not match lastAnswer,
- reject the promise with a newly created InvalidModificationError and abort these
- steps.
- */
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription - answer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateAnswer()
- // assert_session_desc_similar()
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.3. Otherwise, if description is set as a remote description, then run one of
- the following steps:
- - If description is of type "answer", then this completes an offer answer
- negotiation.
-
- Set connection's currentRemoteDescription to description and
- currentLocalDescription to the value of pendingLocalDescription.
-
- Set both pendingRemoteDescription and pendingLocalDescription to null.
-
- Finally setconnection's signaling state to stable.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer))
- .then(answer =>
- pc.setRemoteDescription(answer)
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
-
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.remoteDescription, answer);
-
- assert_session_desc_similar(pc.currentLocalDescription, offer);
- assert_session_desc_similar(pc.currentRemoteDescription, answer);
-
- assert_equals(pc.pendingLocalDescription, null);
- assert_equals(pc.pendingRemoteDescription, null);
-
- assert_array_equals(states, ['have-local-offer', 'stable']);
- })));
- }, 'setRemoteDescription() with valid state and answer should succeed');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.1.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps.
-
- [JSEP]
- 5.6. If the type is "answer", the PeerConnection state MUST be either
- "have-local-offer" or "have-remote-pranswer".
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer()
- .then(offer =>
- promise_rejects_dom(t, 'InvalidStateError',
- pc.setRemoteDescription({ type: 'answer', sdp: offer.sdp })));
- }, 'Calling setRemoteDescription(answer) from stable state should reject with InvalidStateError');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer()
- .then(offer =>
- pc.setRemoteDescription(offer)
- .then(() => generateAnswer(offer)))
- .then(answer =>
- promise_rejects_dom(t, 'InvalidStateError',
- pc.setRemoteDescription(answer)));
- }, 'Calling setRemoteDescription(answer) from have-remote-offer state should reject with InvalidStateError');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription - legacy streams without a=msid lines</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-const FINGERPRINT_SHA256 = '00:00:00:00:00:00:00:00:00:00:00:00:00' +
- ':00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00';
-const ICEUFRAG = 'someufrag';
-const ICEPWD = 'somelongpwdwithenoughrandomness';
-const SDP_BOILERPLATE = 'v=0\r\n' +
- 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
- 's=-\r\n' +
- 't=0 0\r\n';
-const MINIMAL_AUDIO_MLINE =
- 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
- 'c=IN IP4 0.0.0.0\r\n' +
- 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
- 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
- 'a=ice-pwd:' + ICEPWD + '\r\n' +
- 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
- 'a=setup:actpass\r\n' +
- 'a=mid:0\r\n' +
- 'a=sendrecv\r\n' +
- 'a=rtcp-mux\r\n' +
- 'a=rtcp-rsize\r\n' +
- 'a=rtpmap:111 opus/48000/2\r\n';
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const haveOntrack = new Promise(r => pc.ontrack = r);
- await pc.setRemoteDescription({type: 'offer', sdp: SDP_BOILERPLATE + MINIMAL_AUDIO_MLINE});
- assert_equals((await haveOntrack).streams.length, 1);
- }, 'setRemoteDescription with an SDP without a=msid lines triggers ontrack with a default stream.');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription - offer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // assert_session_desc_similar()
- // generateAudioReceiveOnlyOffer
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.3. Otherwise, if description is set as a remote description, then run one of
- the following steps:
- - If description is of type "offer", set connection.pendingRemoteDescription
- attribute to description and signaling state to have-remote-offer.
- */
-
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- pc1.createDataChannel('datachannel');
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
-
- return pc1.createOffer()
- .then(offer => {
- return pc2.setRemoteDescription(offer)
- .then(() => {
- assert_equals(pc2.signalingState, 'have-remote-offer');
- assert_session_desc_similar(pc2.remoteDescription, offer);
- assert_session_desc_similar(pc2.pendingRemoteDescription, offer);
- assert_equals(pc2.currentRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer']);
- });
- });
- }, 'setRemoteDescription with valid offer should succeed');
-
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- pc1.createDataChannel('datachannel');
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
-
- return pc1.createOffer()
- .then(offer => {
- return pc2.setRemoteDescription(offer)
- .then(() => pc2.setRemoteDescription(offer))
- .then(() => {
- assert_equals(pc2.signalingState, 'have-remote-offer');
- assert_session_desc_similar(pc2.remoteDescription, offer);
- assert_session_desc_similar(pc2.pendingRemoteDescription, offer);
- assert_equals(pc2.currentRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer']);
- });
- });
- }, 'setRemoteDescription multiple times should succeed');
-
- promise_test(t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- pc1.createDataChannel('datachannel');
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
-
- return pc1.createOffer()
- .then(offer1 => {
- return pc1.setLocalDescription(offer1)
- .then(()=> {
- return generateAudioReceiveOnlyOffer(pc1)
- .then(offer2 => {
- assert_session_desc_not_similar(offer1, offer2);
-
- return pc2.setRemoteDescription(offer1)
- .then(() => pc2.setRemoteDescription(offer2))
- .then(() => {
- assert_equals(pc2.signalingState, 'have-remote-offer');
- assert_session_desc_similar(pc2.remoteDescription, offer2);
- assert_session_desc_similar(pc2.pendingRemoteDescription, offer2);
- assert_equals(pc2.currentRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer']);
- });
- });
- });
- });
- }, 'setRemoteDescription multiple times with different offer should succeed');
-
- /*
- 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
- error was detected) and abort these steps.
- */
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc1.setRemoteDescription(await pc2.createOffer());
- assert_equals(pc1.signalingState, 'have-remote-offer');
- }, 'setRemoteDescription(offer) from have-local-offer should roll back and succeed');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const srdPromise = pc2.setRemoteDescription(await pc1.createOffer());
-
- assert_equals(pc2.signalingState, "stable", "signalingState should not be set synchronously after a call to sRD");
-
- assert_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should not be set synchronously after a call to sRD");
- assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sRD");
-
- const statePromise = new Promise(resolve => {
- pc2.onsignalingstatechange = () => {
- resolve(pc2.signalingState);
- }
- });
-
- const raceValue = await Promise.race([statePromise, srdPromise]);
- assert_equals(raceValue, "have-remote-offer", "signalingstatechange event should fire before sRD resolves");
- assert_not_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should be updated before the signalingstatechange event");
- assert_equals(pc2.pendingRemoteDescription.type, "offer");
- assert_equals(pc2.pendingRemoteDescription.sdp, pc2.remoteDescription.sdp);
- assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set after a call to sRD(offer)");
-
- await srdPromise;
- }, "setRemoteDescription(offer) in stable should update internal state with a queued task, in the right order");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- await pc1.setLocalDescription(await pc1.createOffer());
- const p = pc1.setRemoteDescription(await pc2.createOffer());
- await new Promise(r => pc1.onsignalingstatechange = r);
- assert_equals(pc1.signalingState, 'stable');
- await pc1.addIceCandidate();
- await p;
- assert_equals(pc1.signalingState, 'have-remote-offer');
- }, 'setRemoteDescription(offer) from have-local-offer is glare-proof');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('video');
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- assert_equals(pc2.getTransceivers().length, 1);
- await pc2.setRemoteDescription(offer);
- assert_equals(pc2.getTransceivers().length, 1);
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- }, 'repeated sRD(offer) works');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('video');
- await exchangeOfferAnswer(pc1, pc2);
- await waitForIceGatheringState(pc1, ['complete']);
- await exchangeOfferAnswer(pc1, pc2);
- await waitForIceStateChange(pc2, ['connected', 'completed']);
- }, 'sRD(reoffer) with candidates and without trickle works');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('video');
- const offer = await pc1.createOffer();
- const srdPromise = pc2.setRemoteDescription(offer);
- assert_equals(pc2.getTransceivers().length, 0);
- await srdPromise;
- assert_equals(pc2.getTransceivers().length, 1);
- }, 'Transceivers added by sRD(offer) should not show up until sRD resolves');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription pranswer</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // generateAnswer
- // assert_session_desc_similar
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setLocalDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? localDescription;
- readonly attribute RTCSessionDescription? currentLocalDescription;
- readonly attribute RTCSessionDescription? pendingLocalDescription;
-
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.1.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps.
-
- [JSEP]
- 5.6. If the type is "pranswer" or "answer", the PeerConnection state MUST be either
- "have-local-offer" or "have-remote-pranswer".
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer()
- .then(offer =>
- promise_rejects_dom(t, 'InvalidStateError',
- pc.setRemoteDescription({ type: 'pranswer', sdp: offer.sdp })));
- }, 'setRemoteDescription(pranswer) from stable state should reject with InvalidStateError');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.3. Otherwise, if description is set as a remote description, then run one
- of the following steps:
- - If description is of type "pranswer", then set
- connection.pendingRemoteDescription to description and signaling state
- to have-remote-pranswer.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer))
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setRemoteDescription(pranswer)
- .then(() => {
- assert_equals(pc.signalingState, 'have-remote-pranswer');
-
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.pendingLocalDescription, offer);
- assert_equals(pc.currentLocalDescription, null);
-
- assert_session_desc_similar(pc.remoteDescription, pranswer);
- assert_session_desc_similar(pc.pendingRemoteDescription, pranswer);
- assert_equals(pc.currentRemoteDescription, null);
-
- assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer']);
- });
- }));
- }, 'setRemoteDescription(pranswer) from have-local-offer state should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer))
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setRemoteDescription(pranswer)
- .then(() => pc.setRemoteDescription(pranswer))
- .then(() => {
- assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer']);
- });
- }));
- }, 'setRemoteDescription(pranswer) multiple times should succeed');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateVideoReceiveOnlyOffer(pc)
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer))
- .then(answer => {
- const pranswer = { type: 'pranswer', sdp: answer.sdp };
-
- return pc.setRemoteDescription(pranswer)
- .then(() => pc.setRemoteDescription(answer))
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
-
- assert_session_desc_similar(pc.localDescription, offer);
- assert_session_desc_similar(pc.currentLocalDescription, offer);
- assert_equals(pc.pendingLocalDescription, null);
-
- assert_session_desc_similar(pc.remoteDescription, answer);
- assert_session_desc_similar(pc.currentRemoteDescription, answer);
- assert_equals(pc.pendingRemoteDescription, null);
-
- assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer', 'stable']);
- });
- }));
- }, 'setRemoteDescription(answer) from have-remote-pranswer state should succeed');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription - replaceTrack</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // getUserMediaTracksAndStreams
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0], streams[0]);
- return sender.replaceTrack(tracks[1])
- .then(t.step_func(() => {
- assert_equals(sender.track, tracks[1]);
- t.done();
- }));
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() sets the track attribute to a new track.');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0], streams[0]);
- return sender.replaceTrack(null)
- .then(t.step_func(() => {
- assert_equals(sender.track, null);
- t.done();
- }));
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() sets the track attribute to null.');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0], streams[0]);
- assert_equals(sender.track, tracks[0]);
- sender.replaceTrack(tracks[1]);
- // replaceTrack() is asynchronous, there should be no synchronously
- // observable effects.
- assert_equals(sender.track, tracks[0]);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() does not set the track synchronously.');
-
- async_test(t => {
- const expectedException = 'InvalidStateError';
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- const sender = caller.addTrack(tracks[0], streams[0]);
- caller.close();
- return sender.replaceTrack(tracks[1])
- .then(t.step_func(() => {
- assert_unreached('Expected replaceTrack() to be rejected with ' +
- expectedException + ' but the promise was resolved.');
- }),
- t.step_func(e => {
- assert_equals(e.name, expectedException);
- t.done();
- }));
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() rejects when the peer connection is closed.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const [tracks, streams] = await getUserMediaTracksAndStreams(2);
- const sender = caller.addTrack(tracks[0], streams[0]);
- caller.removeTrack(sender);
- await sender.replaceTrack(tracks[1]);
- assert_equals(sender.track, tracks[1], "Make sure track gets updated");
- }, 'replaceTrack() does not reject when invoked after removeTrack().');
-
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const [tracks, streams] = await getUserMediaTracksAndStreams(2);
- const sender = caller.addTrack(tracks[0], streams[0]);
- let p = sender.replaceTrack(tracks[1])
- caller.removeTrack(sender);
- await p;
- assert_equals(sender.track, tracks[1], "Make sure track gets updated");
- }, 'replaceTrack() does not reject after a subsequent removeTrack().');
-
- // TODO(hbos): Verify that replaceTrack() changes what media is received on
- // the remote end of two connected peer connections. For video tracks, this
- // requires Chromium's video tag to update on receiving frames when running
- // content_shell. https://crbug.com/793808
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription rollback</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // assert_session_desc_similar
- // generateAudioReceiveOnlyOffer
- // generateDataChannelOffer
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setLocalDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? localDescription;
- readonly attribute RTCSessionDescription? currentLocalDescription;
- readonly attribute RTCSessionDescription? pendingLocalDescription;
-
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.2.3. Otherwise, if description is set as a remote description, then run one
- of the following steps:
- - If description is of type "rollback", then this is a rollback.
- Set connection.pendingRemoteDescription to null and signaling state to stable.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const states = [];
- pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
-
- return generateDataChannelOffer(pc)
- .then(offer => pc.setRemoteDescription(offer))
- .then(() => {
- assert_equals(pc.signalingState, 'have-remote-offer');
- assert_not_equals(pc.remoteDescription, null);
- assert_not_equals(pc.pendingRemoteDescription, null);
- assert_equals(pc.currentRemoteDescription, null);
-
- return pc.setRemoteDescription({type: 'rollback'});
- })
- .then(() => {
- assert_equals(pc.signalingState, 'stable');
- assert_equals(pc.remoteDescription, null);
- assert_equals(pc.pendingRemoteDescription, null);
- assert_equals(pc.currentRemoteDescription, null);
-
- assert_array_equals(states, ['have-remote-offer', 'stable']);
- });
- }, 'setRemoteDescription(rollback) in have-remote-offer state should revert to stable state');
-
- /*
- 4.3.1.6. Set the RTCSessionSessionDescription
- 2.3. If the description's type is invalid for the current signaling state of
- connection, then reject p with a newly created InvalidStateError and abort
- these steps.
-
- [jsep]
- 4.1.8.2. Rollback
- - Rollback can only be used to cancel proposed changes;
- there is no support for rolling back from a stable state to a
- previous stable state
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return promise_rejects_dom(t, 'InvalidStateError',
- pc.setRemoteDescription({type: 'rollback'}));
- }, `setRemoteDescription(rollback) from stable state should reject with InvalidStateError`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return generateAudioReceiveOnlyOffer(pc)
- .then(offer => pc.setRemoteDescription(offer))
- .then(() => pc.setRemoteDescription({
- type: 'rollback',
- sdp: '!<Invalid SDP Content>;'
- }));
- }, `setRemoteDescription(rollback) should ignore invalid sdp content and succeed`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- // We don't use this right away
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const offer1 = await pc1.createOffer();
-
- // Create offer from pc2, apply and rollback on pc1
- pc2.addTransceiver('audio', { direction: 'recvonly' });
- const offer2 = await pc2.createOffer();
- await pc1.setRemoteDescription(offer2);
- await pc1.setRemoteDescription({type: "rollback"});
-
- // Then try applying pc1's old offer
- await pc1.setLocalDescription(offer1);
- }, `local offer created before setRemoteDescription(remote offer) then rollback should still be usable`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- // We don't use this right away. pc1 has provisionally decided that the
- // (only) transceiver is bound to level 0.
- const offer1 = await pc1.createOffer();
-
- // Create offer from pc2, apply and rollback on pc1
- pc2.addTransceiver('audio', { direction: 'recvonly' });
- pc2.addTransceiver('video', { direction: 'recvonly' });
- const offer2 = await pc2.createOffer();
- // pc1 now should change its mind about what level its video transceiver is
- // bound to. It was 0, now it is 1.
- await pc1.setRemoteDescription(offer2);
-
- // Rolling back should put things back the way they were.
- await pc1.setRemoteDescription({type: "rollback"});
-
- // Then try applying pc1's old offer
- await pc1.setLocalDescription(offer1);
- }, "local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.getTransceivers().length, 1);
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 0);
- }, "rollback of a remote offer should remove a transceiver");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.getTransceivers().length, 1);
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- const track = stream2.getVideoTracks()[0];
- await pc2.getTransceivers()[0].sender.replaceTrack(track);
-
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 0);
- }, "rollback of a remote offer should remove touched transceiver");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.getTransceivers().length, 1);
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
-
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 1);
- assert_equals(pc2.getTransceivers()[0].mid, null);
- assert_equals(pc2.getTransceivers()[0].receiver.transport, null);
- }, "rollback of a remote offer should keep a transceiver");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.getTransceivers().length, 1);
-
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 1);
- assert_equals(pc2.getTransceivers()[0].mid, null);
- assert_equals(pc2.getTransceivers()[0].receiver.transport, null);
- }, "rollback of a remote offer should keep a transceiver created by addtrack");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.getTransceivers().length, 1);
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
- await pc2.getTransceivers()[0].sender.replaceTrack(null);
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 1);
- }, "rollback of a remote offer should keep a transceiver without tracks");
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc.addTrack(stream.getTracks()[0], stream);
-
- const states = [];
- const signalingstatechangeResolver = new Resolver();
- pc.onsignalingstatechange = () => {
- states.push(pc.signalingState);
- signalingstatechangeResolver.resolve();
- };
-
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- assert_not_equals(pc.getTransceivers()[0].sender.transport, null);
- await pc.setLocalDescription({type: "rollback"});
- assert_equals(pc.getTransceivers().length, 1);
- assert_equals(pc.getTransceivers()[0].mid, null)
- assert_equals(pc.getTransceivers()[0].sender.transport, null);
- await pc.setLocalDescription(offer);
- assert_equals(pc.getTransceivers().length, 1);
- await signalingstatechangeResolver.promise;
- assert_array_equals(states, ['have-local-offer', 'stable', 'have-local-offer']);
- }, "explicit rollback of local offer should remove transceivers and transport");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- const signalingstatechangeResolver = new Resolver();
- pc1.onsignalingstatechange = () => {
- states.push(pc1.signalingState);
- signalingstatechangeResolver.resolve();
- };
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTransceiver(stream1.getTracks()[0], stream1);
-
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTransceiver(stream2.getTracks()[0], stream2);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- pc1.onnegotiationneeded = t.step_func(() => assert_true(false, "There should be no negotiationneeded event right now"));
- await pc1.setRemoteDescription(await pc2.createOffer());
- await pc1.setLocalDescription(await pc1.createAnswer());
- await signalingstatechangeResolver.promise;
- assert_array_equals(states, ['have-local-offer', 'stable', 'have-remote-offer', 'stable']);
- await new Promise(r => pc1.onnegotiationneeded = r);
- }, "when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const states = [];
- const signalingstatechangeResolver = new Resolver();
- pc1.onsignalingstatechange = () => {
- states.push(pc1.signalingState);
- signalingstatechangeResolver.resolve();
- };
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream1.getTracks()[0], stream1);
-
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- pc1.onnegotiationneeded = t.step_func(() => assert_true(false, "There should be no negotiationneeded event in this test"));
- await pc1.setRemoteDescription(await pc2.createOffer());
- await pc1.setLocalDescription(await pc1.createAnswer());
- assert_array_equals(states, ['have-local-offer', 'stable', 'have-remote-offer', 'stable']);
- await new Promise(r => t.step_timeout(r, 0));
- }, "when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
-
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
-
- // In stable state add video on both end and make sure video transceiver is not killed.
-
- const stream1 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream1.getTracks()[0], stream1);
- await pc1.setLocalDescription(await pc1.createOffer());
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
- const offer2 = await pc2.createOffer();
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 2);
- await pc2.setLocalDescription(offer2);
- }, "rollback of a remote offer to negotiated stable state should enable " +
- "applying of a local offer");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
-
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
-
- // Both ends want to add video at the same time. pc2 rolls back.
-
- const stream2 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
- await pc2.setLocalDescription(await pc2.createOffer());
- assert_equals(pc2.getTransceivers().length, 2);
- assert_not_equals(pc2.getTransceivers()[1].sender.transport, null);
- await pc2.setLocalDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 2);
- // Rollback didn't touch audio transceiver and transport is intact.
- assert_not_equals(pc2.getTransceivers()[0].sender.transport, null);
- // Video transport got killed.
- assert_equals(pc2.getTransceivers()[1].sender.transport, null);
- const stream1 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream1.getTracks()[0], stream1);
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
- }, "rollback of a local offer to negotiated stable state should enable " +
- "applying of a remote offer");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream.getTracks()[0], stream);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
-
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
-
- // pc1 adds video and pc2 adds audio. pc2 rolls back.
- assert_equals(pc2.getTransceivers()[0].direction, "recvonly");
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc2.addTrack(stream2.getTracks()[0], stream2);
- assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
- await pc2.setLocalDescription(await pc2.createOffer());
- assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
- await pc2.setLocalDescription({type: "rollback"});
- assert_equals(pc2.getTransceivers().length, 1);
- // setLocalDescription didn't change direction. So direction remains "sendrecv"
- assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
- // Rollback didn't touch audio transceiver and transport is intact. Still can receive audio.
- assert_not_equals(pc2.getTransceivers()[0].receiver.transport, null);
- const stream1 = await getNoiseStream({video: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream1.getTracks()[0], stream1);
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
- }, "rollback a local offer with audio direction change to negotiated " +
- "stable state and then add video receiver");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver('video', {direction: 'sendonly'});
- pc2.addTransceiver('video', {direction: 'sendonly'});
- await pc1.setLocalDescription(await pc1.createOffer());
- const pc1FirstMid = pc1.getTransceivers()[0].mid;
- await pc2.setLocalDescription(await pc2.createOffer());
- const pc2FirstMid = pc2.getTransceivers()[0].mid;
- // I don't think it is mandated that this has to be true, but any implementation I know of would
- // have predictable mids (e.g. 0, 1, 2...) so pc1 and pc2 should offer with the same mids.
- assert_equals(pc1FirstMid, pc2FirstMid);
- await pc1.setRemoteDescription(pc2.pendingLocalDescription);
- // We've implicitly rolled back and the SRD caused a second transceiver to be created.
- // As such, the first transceiver's mid will now be null, and the second transceiver's mid will
- // match the remote offer.
- assert_equals(pc1.getTransceivers().length, 2);
- assert_equals(pc1.getTransceivers()[0].mid, null);
- assert_equals(pc1.getTransceivers()[1].mid, pc2FirstMid);
- // If we now do an offer the first transceiver will get a different mid than in the first
- // pc1.createOffer()!
- pc1.setLocalDescription(await pc1.createAnswer());
- await pc1.setLocalDescription(await pc1.createOffer());
- assert_not_equals(pc1.getTransceivers()[0].mid, pc1FirstMid);
- }, "two transceivers with same mids");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const audio = stream.getAudioTracks()[0];
- pc1.addTrack(audio, stream);
- const video = stream.getVideoTracks()[0];
- pc1.addTrack(video, stream);
-
- let remoteStream = null;
- pc2.ontrack = e => { remoteStream = e.streams[0]; }
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_true(remoteStream != null);
- let remoteTracks = remoteStream.getTracks();
- const removedTracks = [];
- remoteStream.onremovetrack = e => { removedTracks.push(e.track.id); }
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(removedTracks.length, 2,
- "Rollback should have removed two tracks");
- assert_true(removedTracks.includes(remoteTracks[0].id),
- "First track should be removed");
- assert_true(removedTracks.includes(remoteTracks[1].id),
- "Second track should be removed");
-
- }, "onremovetrack fires during remote rollback");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- pc1.addTrack(stream1.getTracks()[0], stream1);
-
- const offer1 = await pc1.createOffer();
-
- const remoteStreams = [];
- pc2.ontrack = e => { remoteStreams.push(e.streams[0]); }
-
- await pc1.setLocalDescription(offer1);
- await pc2.setRemoteDescription(pc1.pendingLocalDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc1.setRemoteDescription(pc2.localDescription);
-
- assert_equals(remoteStreams.length, 1, "Number of remote streams");
- assert_equals(remoteStreams[0].getTracks().length, 1, "Number of remote tracks");
- const track = remoteStreams[0].getTracks()[0];
-
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- pc1.getTransceivers()[0].sender.setStreams(stream2);
-
- const offer2 = await pc1.createOffer();
- await pc2.setRemoteDescription(offer2);
-
- assert_equals(remoteStreams.length, 2);
- assert_equals(remoteStreams[0].getTracks().length, 0);
- assert_equals(remoteStreams[1].getTracks()[0].id, track.id);
- await pc2.setRemoteDescription({type: "rollback"});
- assert_equals(remoteStreams.length, 3);
- assert_equals(remoteStreams[0].id, remoteStreams[2].id);
- assert_equals(remoteStreams[1].getTracks().length, 0);
- assert_equals(remoteStreams[2].getTracks().length, 1);
- assert_equals(remoteStreams[2].getTracks()[0].id, track.id);
-
- }, "rollback of a remote offer with stream changes");
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc2.addTransceiver('audio');
- const offer = await pc2.createOffer();
- await pc1.setRemoteDescription(offer);
- const [transceiver] = pc1.getTransceivers();
- pc1.setRemoteDescription({type:'rollback'});
- pc1.removeTrack(transceiver.sender);
- }, 'removeTrack() with a sender being rolled back does not crash or throw');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver('video');
- const channel = pc2.createDataChannel('dummy');
- await pc2.setLocalDescription(await pc2.createOffer());
- await pc2.setRemoteDescription(await pc1.createOffer());
- assert_equals(pc2.signalingState, 'have-remote-offer');
- await pc2.setLocalDescription(await pc2.createAnswer());
- await pc2.setLocalDescription(await pc2.createOffer());
- assert_equals(channel.readyState, 'connecting');
- }, 'Implicit rollback with only a datachannel works');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.setRemoteDescription - add/remove remote tracks</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // addEventListenerPromise
- // exchangeOffer
- // exchangeOfferAnswer
- // Resolver
-
- // These tests are concerned with the observable consequences of processing
- // the addition or removal of remote tracks, including events firing and the
- // states of RTCPeerConnection, MediaStream and MediaStreamTrack.
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- caller.addTrack(localStream.getTracks()[0]);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_equals(e.streams.length, 0, 'No remote stream created.');
- });
- await exchangeOffer(caller, callee);
- await ontrackPromise;
- }, 'addTrack() with a track and no stream makes ontrack fire with a track and no stream.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- caller.addTrack(localStream.getTracks()[0], localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_equals(e.streams.length, 1, 'Created a single remote stream.');
- assert_equals(e.streams[0].id, localStream.id,
- 'Local and remote stream IDs match.');
- assert_array_equals(e.streams[0].getTracks(), [e.track],
- 'The remote stream contains the remote track.');
- });
- await exchangeOffer(caller, callee);
- await ontrackPromise;
- }, 'addTrack() with a track and a stream makes ontrack fire with a track and a stream.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let eventSequence = '';
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- caller.addTrack(localStream.getTracks()[0], localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- eventSequence += 'ontrack;';
- });
- await exchangeOffer(caller, callee);
- eventSequence += 'setRemoteDescription;';
- await ontrackPromise;
- assert_equals(eventSequence, 'ontrack;setRemoteDescription;');
- }, 'ontrack fires before setRemoteDescription resolves.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStreams = await Promise.all([
- getNoiseStream({audio: true}),
- getNoiseStream({audio: true}),
- ]);
- t.add_cleanup(() => localStreams.forEach((stream) =>
- stream.getTracks().forEach((track) => track.stop())));
- caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
- caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
- let ontrackEventsFired = 0;
- const ontrackEventResolvers = [ new Resolver(), new Resolver() ];
- callee.ontrack = t.step_func(e => {
- ontrackEventResolvers[ontrackEventsFired++].resolve(e);
- });
- await exchangeOffer(caller, callee);
- let firstTrackEvent = await ontrackEventResolvers[0];
- assert_equals(firstTrackEvent.streams.length, 1,
- 'First ontrack fires with a single stream.');
- assert_equals(firstTrackEvent.streams[0].id,
- localStreams[0].id,
- 'First ontrack\'s stream ID matches local stream.');
- let secondTrackEvent = await ontrackEventResolvers[1];
- assert_equals(secondTrackEvent.streams.length, 1,
- 'Second ontrack fires with a single stream.');
- assert_equals(secondTrackEvent.streams[0].id,
- localStreams[0].id,
- 'Second ontrack\'s stream ID matches local stream.');
- assert_array_equals(firstTrackEvent.streams, secondTrackEvent.streams,
- 'ontrack was fired with the same streams both times.');
-
- assert_equals(firstTrackEvent.streams[0].getTracks().length, 2, "stream should have two tracks");
- assert_true(firstTrackEvent.streams[0].getTracks().includes(firstTrackEvent.track), "remoteStream should have the first track");
- assert_true(firstTrackEvent.streams[0].getTracks().includes(secondTrackEvent.track), "remoteStream should have the second track");
- assert_equals(ontrackEventsFired, 2, 'Unexpected number of track events.');
-
- assert_equals(ontrackEventsFired, 2, 'Unexpected number of track events.');
- }, 'addTrack() with two tracks and one stream makes ontrack fire twice with the tracks and shared stream.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let eventSequence = '';
- const localStreams = await Promise.all([
- getNoiseStream({audio: true}),
- getNoiseStream({audio: true}),
- ]);
- t.add_cleanup(() => localStreams.forEach((stream) =>
- stream.getTracks().forEach((track) => track.stop())));
- caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
- const remoteStreams = [];
- callee.ontrack = e => {
- if (!remoteStreams.includes(e.streams[0]))
- remoteStreams.push(e.streams[0]);
- };
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- assert_equals(remoteStreams.length, 1, 'One remote stream created.');
- assert_equals(remoteStreams[0].id, localStreams[0].id,
- 'First local and remote streams have the same ID.');
- const firstRemoteTrack = remoteStreams[0].getTracks()[0];
- const onaddtrackPromise = addEventListenerPromise(t, remoteStreams[0], 'addtrack');
- caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
- await exchangeOffer(caller, callee);
- const e = await onaddtrackPromise;
- assert_equals(remoteStreams[0].getTracks().length, 2, 'stream has two tracks');
- assert_not_equals(e.track.id, firstRemoteTrack.id,
- 'addtrack event has a new track');
- assert_equals(remoteStreams.length, 1, 'Still a single remote stream.');
- }, 'addTrack() for an existing stream makes stream.onaddtrack fire.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let eventSequence = '';
- const localStreams = await Promise.all([
- getNoiseStream({audio: true}),
- getNoiseStream({audio: true}),
- ]);
- t.add_cleanup(() => localStreams.forEach((stream) =>
- stream.getTracks().forEach((track) => track.stop())));
- caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
- const remoteStreams = [];
- callee.ontrack = e => {
- if (!remoteStreams.includes(e.streams[0]))
- remoteStreams.push(e.streams[0]);
- };
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- assert_equals(remoteStreams.length, 1, 'One remote stream created.');
- const onaddtrackPromise =
- addEventListenerPromise(t, remoteStreams[0], 'addtrack', e => {
- eventSequence += 'stream.onaddtrack;';
- });
- caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
- await exchangeOffer(caller, callee);
- eventSequence += 'setRemoteDescription;';
- await onaddtrackPromise;
- assert_equals(remoteStreams.length, 1, 'Still a single remote stream.');
- assert_equals(eventSequence, 'stream.onaddtrack;setRemoteDescription;');
- }, 'stream.onaddtrack fires before setRemoteDescription resolves.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStreams = await Promise.all([
- getNoiseStream({audio: true}),
- getNoiseStream({audio: true}),
- ]);
- t.add_cleanup(() => localStreams.forEach((stream) =>
- stream.getTracks().forEach((track) => track.stop())));
- caller.addTrack(localStreams[0].getTracks()[0],
- localStreams[0], localStreams[1]);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_equals(e.streams.length, 2, 'Two remote stream created.');
- assert_array_equals(e.streams[0].getTracks(), [e.track],
- 'First remote stream == [remote track].');
- assert_array_equals(e.streams[1].getTracks(), [e.track],
- 'Second remote stream == [remote track].');
- assert_equals(e.streams[0].id, localStreams[0].id,
- 'First local and remote stream IDs match.');
- assert_equals(e.streams[1].id, localStreams[1].id,
- 'Second local and remote stream IDs match.');
- });
- await exchangeOffer(caller, callee);
- await ontrackPromise;
- }, 'addTrack() with a track and two streams makes ontrack fire with a track and two streams.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- caller.addTrack(localStream.getTracks()[0], localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_array_equals(callee.getReceivers(), [e.receiver],
- 'getReceivers() == [e.receiver].');
- });
- await exchangeOffer(caller, callee);
- await ontrackPromise;
- }, 'ontrack\'s receiver matches getReceivers().');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- const sender = caller.addTrack(localStream.getTracks()[0], localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track');
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await ontrackPromise;
- assert_equals(callee.getReceivers().length, 1, 'One receiver created.');
- caller.removeTrack(sender);
- await exchangeOffer(caller, callee);
- assert_equals(callee.getReceivers().length, 1, 'Receiver not removed.');
- }, 'removeTrack() does not remove the receiver.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- const [track] = localStream.getTracks();
- const sender = caller.addTrack(track, localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_equals(e.streams.length, 1);
- return e.streams[0];
- });
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- const remoteStream = await ontrackPromise;
- const remoteTrack = remoteStream.getTracks()[0];
- const onremovetrackPromise =
- addEventListenerPromise(t, remoteStream, 'removetrack', e => {
- assert_equals(e.track, remoteTrack);
- assert_equals(remoteStream.getTracks().length, 0,
- 'Remote stream emptied of tracks.');
- });
- caller.removeTrack(sender);
- await exchangeOffer(caller, callee);
- await onremovetrackPromise;
- }, 'removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream.');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let eventSequence = '';
- const localStream =
- await getNoiseStream({audio: true});
- t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
- const sender = caller.addTrack(localStream.getTracks()[0], localStream);
- const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
- assert_equals(e.streams.length, 1);
- return e.streams[0];
- });
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- const remoteStream = await ontrackPromise;
- const remoteTrack = remoteStream.getTracks()[0];
- const onremovetrackPromise =
- addEventListenerPromise(t, remoteStream, 'removetrack', e => {
- eventSequence += 'stream.onremovetrack;';
- });
- caller.removeTrack(sender);
- await exchangeOffer(caller, callee);
- eventSequence += 'setRemoteDescription;';
- await onremovetrackPromise;
- assert_equals(eventSequence, 'stream.onremovetrack;setRemoteDescription;');
- }, 'stream.onremovetrack fires before setRemoteDescription resolves.');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const sender = pc.addTrack(stream.getTracks()[0]);
- pc.removeTrack(sender);
- pc.removeTrack(sender);
- }, 'removeTrack() twice is safe.');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.setRemoteDescription</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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:
- // assert_session_desc_not_similar()
- // assert_session_desc_similar()
-
- /*
- 4.3.2. Interface Definition
- [Constructor(optional RTCConfiguration configuration)]
- interface RTCPeerConnection : EventTarget {
- Promise<void> setRemoteDescription(
- RTCSessionDescriptionInit description);
-
- readonly attribute RTCSessionDescription? remoteDescription;
- readonly attribute RTCSessionDescription? currentRemoteDescription;
- readonly attribute RTCSessionDescription? pendingRemoteDescription;
- ...
- };
-
- 4.6.2. RTCSessionDescription Class
- dictionary RTCSessionDescriptionInit {
- required RTCSdpType type;
- DOMString sdp = "";
- };
-
- 4.6.1. RTCSdpType
- enum RTCSdpType {
- "offer",
- "pranswer",
- "answer",
- "rollback"
- };
- */
-
- /*
- 4.6.1. enum RTCSdpType
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- // SDP is validated after WebIDL validation
- try {
- await pc.setRemoteDescription({ type: 'bogus', sdp: 'bogus' });
- t.unreached_func("Should have rejected.");
- } catch (e) {
- assert_throws_js(TypeError, () => { throw e });
- }
- }, 'setRemoteDescription with invalid type and invalid SDP should reject with TypeError');
-
- /* Dedicated signalingstate events test. */
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- t.add_cleanup(() => pc2.close());
-
- let eventCount = 0;
- const states = [
- 'stable', 'have-local-offer', 'stable', 'have-remote-offer',
- ];
- pc.onsignalingstatechange = t.step_func(() =>
- assert_equals(pc.signalingState, states[++eventCount]));
-
- const assert_state = state => {
- assert_equals(state, pc.signalingState);
- assert_equals(state, states[eventCount]);
- };
-
- const offer = await generateAudioReceiveOnlyOffer(pc);
- assert_state('stable');
- await pc.setLocalDescription(offer);
- assert_state('have-local-offer');
- await pc2.setRemoteDescription(offer);
- await exchangeAnswer(pc, pc2);
- assert_state('stable');
- await exchangeOffer(pc2, pc);
- assert_state('have-remote-offer');
- }, 'Negotiation should fire signalingsstate events');
-
- /* Operations after returning to stable state */
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- t.add_cleanup(() => pc2.close());
-
- const offer1 = await generateAudioReceiveOnlyOffer(pc2);
- await pc2.setLocalDescription(offer1);
- await pc.setRemoteDescription(offer1);
- await exchangeAnswer(pc2, pc);
- const offer2 = await generateVideoReceiveOnlyOffer(pc2);
- await pc2.setLocalDescription(offer2);
- await pc.setRemoteDescription(offer2);
- assert_session_desc_not_similar(offer1, offer2);
- assert_session_desc_similar(pc.remoteDescription, offer2);
- assert_session_desc_similar(pc.currentRemoteDescription, offer1);
- assert_session_desc_similar(pc.pendingRemoteDescription, offer2);
- }, 'Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- t.add_cleanup(() => pc2.close());
-
- const offer = await generateAudioReceiveOnlyOffer(pc);
- await pc.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc.setRemoteDescription(answer);
- await exchangeOffer(pc2, pc);
- assert_equals(pc.remoteDescription.sdp, pc.pendingRemoteDescription.sdp);
- assert_session_desc_similar(pc.remoteDescription, offer);
- assert_session_desc_similar(pc.currentRemoteDescription, answer);
- }, 'Switching role from offerer to answerer after going back to stable state should succeed');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const offer = await pc.createOffer();
- const p = Promise.race([
- pc.setRemoteDescription(offer),
- new Promise(r => t.step_timeout(() => r("timeout"), 200))
- ]);
- pc.close();
- assert_equals(await p, "timeout");
- assert_equals(pc.signalingState, "closed", "In closed state");
- }, 'Closing on setRemoteDescription() neither resolves nor rejects');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- const p = Promise.race([
- pc.setRemoteDescription(offer),
- new Promise(r => t.step_timeout(() => r("timeout"), 200))
- ]);
- pc.close();
- assert_equals(await p, "timeout");
- assert_equals(pc.signalingState, "closed", "In closed state");
- }, 'Closing on rollback neither resolves nor rejects');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection.prototype.getStats</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCStats-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // exchangeOfferAnswer
- // getUserMediaTracksAndStreams
- // waitForRtpAndRtcpStats
-
- // The following helper functions are called from RTCStats-helper.js
- // (depends on dictionary-helper.js):
- // validateRtcStats
-
- async_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- let track;
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- track = tracks[0];
- pc.addTrack(track, streams[0]);
- return pc.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', track.id);
- assert_true(trackStats != null, 'Has stats for track');
- // TODO(hbos): Here and elsewhere, validateRtcStats() only tests id,
- // timestamp and type is correct type. Should validate based on stats type
- // but it expects both audio and video members.
- // https://github.com/web-platform-tests/wpt/issues/9010
- validateRtcStats(report, trackStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'addTrack() without setLocalDescription() yields track stats');
-
- async_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- let track;
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- track = tracks[0];
- pc.addTrack(track, streams[0]);
- return pc.createOffer();
- }))
- .then(t.step_func(offer => {
- return pc.setLocalDescription(offer);
- }))
- .then(t.step_func(() => {
- return pc.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', track.id);
- assert_true(trackStats != null, 'Has stats for track');
- validateRtcStats(report, trackStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'addTrack() with setLocalDescription() yields track stats');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let sendingTrack;
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- sendingTrack = tracks[0];
- caller.addTrack(sendingTrack, streams[0]);
- return exchangeOfferAnswer(caller, callee);
- }))
- .then(t.step_func(() => {
- return caller.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack.id);
- assert_true(trackStats != null, 'Has stats for sending track');
- let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
- 'trackId', trackStats.id);
- assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
- validateRtcStats(report, trackStats);
- validateRtcStats(report, outboundStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'O/A exchange yields outbound RTP stream stats for sending track');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let receivingTrack;
- callee.ontrack = trackEvent => {
- assert_equals(receivingTrack, undefined, 'ontrack has not fired before');
- receivingTrack = trackEvent.track;
- };
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- caller.addTrack(tracks[0], streams[0]);
- return exchangeOfferAnswer(caller, callee);
- }))
- .then(t.step_func(() => {
- return callee.getStats();
- }))
- .then(t.step_func(report => {
- assert_true(receivingTrack != null, 'Has a receiving track');
- let trackStats = findStatsByTypeAndId(report, 'track', receivingTrack.id);
- assert_true(trackStats != null, 'Has stats for receiving track');
- let inboundStats = findStatsByTypeAndMember(report, 'inbound-rtp',
- 'trackId', trackStats.id);
- assert_true(inboundStats != null, 'Has stats for outbound RTP stream');
- validateRtcStats(report, trackStats);
- validateRtcStats(report, inboundStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'O/A exchange yields inbound RTP stream stats for receiving track');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let sendingTrack1;
- let sendingTrack2;
- let sender;
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- sendingTrack1 = tracks[0];
- sendingTrack2 = tracks[1];
- sender = caller.addTrack(sendingTrack1, streams[0]);
- return sender.replaceTrack(sendingTrack2);
- }))
- .then(t.step_func(() => {
- return caller.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
- assert_true(trackStats != null, 'Has stats for replaced track');
- validateRtcStats(report, trackStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() before offer: new track attachment stats present');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let sendingTrack1;
- let sendingTrack2;
- let sender;
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- sendingTrack1 = tracks[0];
- sendingTrack2 = tracks[1];
- sender = caller.addTrack(sendingTrack1, streams[0]);
- return exchangeOffer(caller, callee);
- }))
- .then(t.step_func(() => {
- return sender.replaceTrack(sendingTrack2);
- }))
- .then(t.step_func(() => {
- return caller.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
- assert_true(trackStats != null, 'Has stats for replaced track');
- let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
- 'trackId', trackStats.id);
- assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
- validateRtcStats(report, trackStats);
- validateRtcStats(report, outboundStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() after offer, before answer: new track attachment stats ' +
- 'present');
-
- async_test(t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let sendingTrack1;
- let sendingTrack2;
- let sender;
- getUserMediaTracksAndStreams(2)
- .then(t.step_func(([tracks, streams]) => {
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- sendingTrack1 = tracks[0];
- sendingTrack2 = tracks[1];
- sender = caller.addTrack(sendingTrack1, streams[0]);
- return exchangeOfferAnswer(caller, callee);
- }))
- .then(t.step_func(() => {
- return sender.replaceTrack(sendingTrack2);
- }))
- .then(t.step_func(() => {
- return caller.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
- assert_true(trackStats != null, 'Has stats for replaced track');
- let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
- 'trackId', trackStats.id);
- assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
- validateRtcStats(report, trackStats);
- validateRtcStats(report, outboundStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'replaceTrack() after answer: new track attachment stats present');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(2);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- let sender = caller.addTrack(tracks[0], streams[0]);
- callee.addTrack(tracks[1], streams[1]);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await listenToConnected(caller);
- let receiver = caller.getReceivers()[0];
-
- // Obtain inbound and outbound RTP stream stats on a full stats report.
- let fullReport = await caller.getStats();
- let outboundTrackStats = findStatsByTypeAndId(
- fullReport, 'track', sender.track.id);
- let outboundStats = findStatsByTypeAndMember(
- fullReport, 'outbound-rtp', 'trackId', outboundTrackStats.id);
- assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
- let inboundTrackStats = findStatsByTypeAndId(
- fullReport, 'track', receiver.track.id);
- let inboundStats = findStatsByTypeAndMember(
- fullReport, 'inbound-rtp', 'trackId', inboundTrackStats.id);
- assert_true(inboundStats != null, 'Has stats for inbound RTP stream');
-
- // Perform stats selection algorithm with sender selector. The result should
- // contain the outbound-rtp but not the inbound-rtp.
- let senderReport = await sender.getStats();
- assert_true(senderReport.has(outboundStats.id));
- assert_false(senderReport.has(inboundStats.id));
-
- // Validate the stats graph, ensuring all stats objects are reachable and
- // valid from the outbound-rtp stats.
- validateStatsGraph(senderReport, senderReport.get(outboundStats.id));
- // Ensure that the stats graph contains some expected dictionaries.
- assert_equals(findStatsOfType(senderReport, 'track').length, 1,
- 'senderReport should contain track stats');
- assert_equals(findStatsOfType(senderReport, 'transport').length, 1,
- 'senderReport should contain transport stats');
- assert_equals(findStatsOfType(senderReport, 'candidate-pair').length, 1,
- 'senderReport should contain candidate-pair stats');
- assert_equals(findStatsOfType(senderReport, 'local-candidate').length, 1,
- 'senderReport should contain local-candidate stats');
- assert_equals(findStatsOfType(senderReport, 'remote-candidate').length, 1,
- 'senderReport should contain remote-candidate stats');
- }, 'RTCRtpSender.getStats() contains only outbound-rtp and related stats');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(2);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- let sender = caller.addTrack(tracks[0], streams[0]);
- callee.addTrack(tracks[1], streams[1]);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await listenToConnected(caller);
- let receiver = caller.getReceivers()[0];
-
- // Obtain inbound and outbound RTP stream stats on a full stats report.
- let fullReport = await caller.getStats();
- let outboundTrackStats = findStatsByTypeAndId(
- fullReport, 'track', sender.track.id);
- let outboundStats = findStatsByTypeAndMember(
- fullReport, 'outbound-rtp', 'trackId', outboundTrackStats.id);
- assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
- let inboundTrackStats = findStatsByTypeAndId(
- fullReport, 'track', receiver.track.id);
- let inboundStats = findStatsByTypeAndMember(
- fullReport, 'inbound-rtp', 'trackId', inboundTrackStats.id);
- assert_true(inboundStats != null, 'Has stats for inbound RTP stream');
-
- // Perform stats selection algorithm with receiver selector. The result
- // should contain the inbound-rtp but not the outbound-rtp.
- let receiverReport = await receiver.getStats();
- assert_true(receiverReport.has(inboundStats.id));
- assert_false(receiverReport.has(outboundStats.id));
-
- // Validate the stats graph, ensuring all stats objects are reachable and
- // valid from the outbound-rtp stats.
- validateStatsGraph(receiverReport, receiverReport.get(inboundStats.id));
- // Ensure that the stats graph contains some expected dictionaries.
- assert_equals(findStatsOfType(receiverReport, 'track').length, 1,
- 'receiverReport should contain track stats');
- assert_equals(findStatsOfType(receiverReport, 'transport').length, 1,
- 'receiverReport should contain transport stats');
- assert_equals(findStatsOfType(receiverReport, 'candidate-pair').length, 1,
- 'receiverReport should contain candidate-pair stats');
- assert_equals(findStatsOfType(receiverReport, 'local-candidate').length, 1,
- 'receiverReport should contain local-candidate stats');
- assert_equals(findStatsOfType(receiverReport, 'remote-candidate').length, 1,
- 'receiverReport should contain remote-candidate stats');
- }, 'RTCRtpReceiver.getStats() contains only inbound-rtp and related stats');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(2);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- let sender = caller.addTrack(tracks[0], streams[0]);
- callee.addTrack(tracks[1], streams[1]);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await listenToIceConnected(caller);
-
- // Wait until RTCP has arrived so that it can not arrive between
- // the two get stats calls.
- await waitForRtpAndRtcpStats(caller);
-
- let senderReport = await sender.getStats();
- let trackReport = await caller.getStats(sender.track);
-
- // Verify the same stats objects are returned but don't compare each
- // individual metric because timestamps and counters could have gone up
- // between the two getStats() calls.
- senderReport.forEach(senderReportStat => {
- assert_true(trackReport.has(senderReportStat.id));
- });
- trackReport.forEach(trackReportStat => {
- assert_true(senderReport.has(trackReportStat.id));
- });
- }, 'RTCPeerConnection.getStats(sendingTrack) is the same as ' +
- 'RTCRtpSender.getStats()');
-
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(2);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- let sender = caller.addTrack(tracks[0], streams[0]);
- callee.addTrack(tracks[1], streams[1]);
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAnswer(caller, callee);
- await listenToIceConnected(caller);
- let receiver = caller.getReceivers()[0];
-
- // Wait until RTCP has arrived so that it can not arrive between
- // the two get stats calls.
- await waitForRtpAndRtcpStats(caller);
-
- let receiverReport = await receiver.getStats();
- let trackReport = await caller.getStats(receiver.track);
-
- // Verify the same stats objects are returned but don't compare each
- // individual metric because timestamps and counters could have gone up
- // between the two getStats() calls.
- receiverReport.forEach(receiverReportStat => {
- assert_true(trackReport.has(receiverReportStat.id));
- });
- trackReport.forEach(trackReportStat => {
- assert_true(receiverReport.has(trackReportStat.id));
- });
- }, 'RTCPeerConnection.getStats(receivingTrack) is the same as ' +
- 'RTCRtpReceiver.getStats()');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(1);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(tracks[0]));
- }, 'RTCPeerConnection.getStats(track) throws InvalidAccessError when there ' +
- 'are zero senders or receivers for the track');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- let [tracks, streams] = await getUserMediaTracksAndStreams(2);
- t.add_cleanup(() => tracks.forEach(track => track.stop()));
- let sender1 = pc.addTrack(tracks[0], streams[0]);
- let sender2 = pc.addTrack(tracks[1], streams[1]);
- await sender2.replaceTrack(sender1.track);
- await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(sender1.track));
- }, 'RTCPeerConnection.getStats(track) throws InvalidAccessError when there ' +
- 'are multiple senders for the track');
-
- // Helpers.
-
- function findStatsByTypeAndId(report, type, identifier) {
- return findStats(report, stats => {
- return stats.type == type && stats[type + 'Identifier'] == identifier;
- });
- }
-
- function findStatsByTypeAndMember(report, type, member, value) {
- return findStats(report, stats => {
- return stats.type == type && stats[member] == value;
- });
- }
-
- function findStats(report, findFunc) {
- for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
- if (findFunc(n.value))
- return n.value;
- }
- return null;
- }
-
- function findStatsOfType(report, type) {
- let stats = [];
- for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
- if (n.value.type == type)
- stats.push(n.value);
- }
- return stats;
- }
-
- // Explores the stats graph starting from |stat|, validating each stat
- // (validateRtcStats) and asserting that all stats of the report were visited.
- function validateStatsGraph(report, stat) {
- let visitedIds = new Set();
- validateStatsGraphRecursively(report, stat.id, visitedIds);
- assert_equals(visitedIds.size, report.size,
- 'Entire stats graph should have been explored.')
- }
-
- function validateStatsGraphRecursively(report, currentId, visitedIds) {
- if (visitedIds.has(currentId))
- return;
- visitedIds.add(currentId);
- assert_true(report.has(currentId), 'Broken reference.');
- let stat = report.get(currentId);
- validateRtcStats(report, stat);
- for (let member in stat) {
- if (member.endsWith('Id')) {
- validateStatsGraphRecursively(report, stat[member], visitedIds);
- } else if (member.endsWith('Ids')) {
- let ids = stat[member];
- for (let i = 0; i < ids.length; ++i) {
- validateStatsGraphRecursively(report, ids[i], visitedIds);
- }
- }
- }
- }
-</script>
+++ /dev/null
-<!doctype html>
-<meta name="timeout" content="long"/>
-<meta charset=utf-8>
-<title>RTCPeerConnection-transceivers.https.html</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// exchangeOffer
-// exchangeOfferAndListenToOntrack
-// exchangeAnswer
-// exchangeAnswerAndListenToOntrack
-// addEventListenerPromise
-// createPeerConnectionWithCleanup
-// createTrackAndStreamWithCleanup
-// findTransceiverForSender
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const sender = pc.addTrack(track, stream);
- const transceiver = findTransceiverForSender(pc, sender);
- assert_true(transceiver instanceof RTCRtpTransceiver);
- assert_true(transceiver.sender instanceof RTCRtpSender);
- assert_equals(transceiver.sender, sender);
-}, 'addTrack: creates a transceiver for the sender');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_array_equals(pc.getTransceivers(), [transceiver],
- 'pc.getTransceivers() equals [transceiver]');
- assert_array_equals(pc.getSenders(), [transceiver.sender],
- 'pc.getSenders() equals [transceiver.sender]');
- assert_array_equals(pc.getReceivers(), [transceiver.receiver],
- 'pc.getReceivers() equals [transceiver.receiver]');
-}, 'addTrack: "transceiver == {sender,receiver}"');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_true(transceiver.sender.track instanceof MediaStreamTrack,
- 'transceiver.sender.track instanceof MediaStreamTrack');
- assert_equals(transceiver.sender.track, track,
- 'transceiver.sender.track == track');
-}, 'addTrack: transceiver.sender is associated with the track');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_true(transceiver.receiver instanceof RTCRtpReceiver,
- 'transceiver.receiver instanceof RTCRtpReceiver');
- assert_true(transceiver.receiver.track instanceof MediaStreamTrack,
- 'transceiver.receiver.track instanceof MediaStreamTrack');
- assert_not_equals(transceiver.receiver.track, track,
- 'transceiver.receiver.track != track');
-}, 'addTrack: transceiver.receiver has its own track');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_true(transceiver.receiver.track.muted);
-}, 'addTrack: transceiver.receiver\'s track is muted');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_equals(transceiver.mid, null);
-}, 'addTrack: transceiver is not associated with an m-section');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
- assert_false(transceiver.stopped);
-}, 'addTrack: transceiver is not stopped');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_equals(transceiver.direction, 'sendrecv');
-}, 'addTrack: transceiver\'s direction is sendrecv');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- assert_equals(transceiver.currentDirection, null);
-}, 'addTrack: transceiver\'s currentDirection is null');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- await pc.setLocalDescription(await pc.createOffer());
- assert_not_equals(transceiver.mid, null, 'transceiver.mid != null');
-}, 'setLocalDescription(offer): transceiver gets associated with an m-section');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- let sdp = offer.sdp;
- let sdpMidLineStart = sdp.indexOf('a=mid:');
- let sdpMidLineEnd = sdp.indexOf('\r\n', sdpMidLineStart);
- assert_true(sdpMidLineStart != -1 && sdpMidLineEnd != -1,
- 'Failed to parse offer SDP for a=mid');
- let parsedMid = sdp.substring(sdpMidLineStart + 6, sdpMidLineEnd);
- assert_equals(transceiver.mid, parsedMid, 'transceiver.mid == parsedMid');
-}, 'setLocalDescription(offer): transceiver.mid matches the offer SDP');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_true(trackEvent instanceof RTCTrackEvent,
- 'trackEvent instanceof RTCTrackEvent');
- assert_true(trackEvent.track instanceof MediaStreamTrack,
- 'trackEvent.track instanceof MediaStreamTrack');
-}, 'setRemoteDescription(offer): ontrack fires with a track');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- pc1.addTrack(track, stream);
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_true(trackEvent.track instanceof MediaStreamTrack,
- 'trackEvent.track instanceof MediaStreamTrack');
- assert_equals(trackEvent.streams.length, 1,
- 'trackEvent contains a single stream');
- assert_true(trackEvent.streams[0] instanceof MediaStream,
- 'trackEvent has a MediaStream');
- assert_equals(trackEvent.streams[0].id, stream.id,
- 'trackEvent.streams[0].id == stream.id');
-}, 'setRemoteDescription(offer): ontrack\'s stream.id is the same as stream.id');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_true(trackEvent.transceiver instanceof RTCRtpTransceiver,
- 'trackEvent.transceiver instanceof RTCRtpTransceiver');
-}, 'setRemoteDescription(offer): ontrack fires with a transceiver.');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(transceiver.mid, trackEvent.transceiver.mid);
-}, 'setRemoteDescription(offer): transceiver.mid is the same on both ends');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- const transceiver = trackEvent.transceiver;
- assert_array_equals(pc2.getTransceivers(), [transceiver],
- 'pc2.getTransceivers() equals [transceiver]');
- assert_array_equals(pc2.getSenders(), [transceiver.sender],
- 'pc2.getSenders() equals [transceiver.sender]');
- assert_array_equals(pc2.getReceivers(), [transceiver.receiver],
- 'pc2.getReceivers() equals [transceiver.receiver]');
-}, 'setRemoteDescription(offer): "transceiver == {sender,receiver}"');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.transceiver.direction, 'recvonly');
-}, 'setRemoteDescription(offer): transceiver.direction is recvonly');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.transceiver.currentDirection, null);
-}, 'setRemoteDescription(offer): transceiver.currentDirection is null');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
- assert_false(trackEvent.transceiver.stopped);
-}, 'setRemoteDescription(offer): transceiver.stopped is false');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const pc2 = createPeerConnectionWithCleanup(t);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- const transceiver = trackEvent.transceiver;
- assert_equals(transceiver.currentDirection, null,
- 'SRD(offer): transceiver.currentDirection is null');
- await pc2.setLocalDescription(await pc2.createAnswer());
- assert_equals(transceiver.currentDirection, 'recvonly',
- 'SLD(answer): transceiver.currentDirection is recvonly');
-}, 'setLocalDescription(answer): transceiver.currentDirection is recvonly');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
- const pc2 = createPeerConnectionWithCleanup(t);
- await exchangeOffer(pc1, pc2);
- assert_equals(transceiver.currentDirection, null,
- 'SLD(offer): transceiver.currentDirection is null');
- await exchangeAnswer(pc1, pc2);
- assert_equals(transceiver.currentDirection, 'sendonly',
- 'SRD(answer): transceiver.currentDirection is sendonly');
-}, 'setLocalDescription(answer): transceiver.currentDirection is sendonly');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver(track);
- assert_true(transceiver instanceof RTCRtpTransceiver);
- assert_true(transceiver.sender instanceof RTCRtpSender);
- assert_true(transceiver.receiver instanceof RTCRtpReceiver);
- assert_equals(transceiver.sender.track, track);
-}, 'addTransceiver(track): creates a transceiver for the track');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver(track);
- assert_array_equals(pc.getTransceivers(), [transceiver],
- 'pc.getTransceivers() equals [transceiver]');
- assert_array_equals(pc.getSenders(), [transceiver.sender],
- 'pc.getSenders() equals [transceiver.sender]');
- assert_array_equals(pc.getReceivers(), [transceiver.receiver],
- 'pc.getReceivers() equals [transceiver.receiver]');
-}, 'addTransceiver(track): "transceiver == {sender,receiver}"');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver(track, {direction:'inactive'});
- assert_equals(transceiver.direction, 'inactive');
-}, 'addTransceiver(track, init): initialize direction to inactive');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const otherPc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver(track, {
- sendEncodings: [{active:false}]
- });
-
- // Negotiate parameters.
- const offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- await otherPc.setRemoteDescription(offer);
- const answer = await otherPc.createAnswer();
- await otherPc.setLocalDescription(answer);
- await pc.setRemoteDescription(answer);
-
- const params = transceiver.sender.getParameters();
- assert_false(params.encodings[0].active);
-}, 'addTransceiver(track, init): initialize sendEncodings[0].active to false');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- pc1.addTransceiver(track, {streams:[]});
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
-}, 'addTransceiver(0 streams): ontrack fires with no stream');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- const stream = new MediaStream();
- pc1.addTransceiver(track, {streams:[stream]});
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
- assert_equals(trackEvent.streams[0].id, stream.id,
- 'trackEvent.streams[0].id == stream.id');
-}, 'addTransceiver(1 stream): ontrack fires with corresponding stream');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- const stream0 = new MediaStream();
- const stream1 = new MediaStream();
- pc1.addTransceiver(track, {streams:[stream0, stream1]});
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
- assert_equals(trackEvent.streams[0].id, stream0.id,
- 'trackEvent.streams[0].id == stream0.id');
- assert_equals(trackEvent.streams[1].id, stream1.id,
- 'trackEvent.streams[1].id == stream1.id');
-}, 'addTransceiver(2 streams): ontrack fires with corresponding two streams');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- pc1.addTrack(track);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
-}, 'addTrack(0 streams): ontrack fires with no stream');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- const stream = new MediaStream();
- pc1.addTrack(track, stream);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
- assert_equals(trackEvent.streams[0].id, stream.id,
- 'trackEvent.streams[0].id == stream.id');
-}, 'addTrack(1 stream): ontrack fires with corresponding stream');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track] = await createTrackAndStreamWithCleanup(t);
- const stream0 = new MediaStream();
- const stream1 = new MediaStream();
- pc1.addTrack(track, stream0, stream1);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
- assert_equals(trackEvent.streams[0].id, stream0.id,
- 'trackEvent.streams[0].id == stream0.id');
- assert_equals(trackEvent.streams[1].id, stream1.id,
- 'trackEvent.streams[1].id == stream1.id');
-}, 'addTrack(2 streams): ontrack fires with corresponding two streams');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.direction, 'sendrecv');
-}, 'addTransceiver(\'audio\'): creates a transceiver with direction sendrecv');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.receiver.track.kind, 'audio');
-}, 'addTransceiver(\'audio\'): transceiver.receiver.track.kind == \'audio\'');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('video');
- assert_equals(transceiver.receiver.track.kind, 'video');
-}, 'addTransceiver(\'video\'): transceiver.receiver.track.kind == \'video\'');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.sender.track, null);
-}, 'addTransceiver(\'audio\'): transceiver.sender.track == null');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.currentDirection, null);
-}, 'addTransceiver(\'audio\'): transceiver.currentDirection is null');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const transceiver = pc.addTransceiver('audio');
- // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
- assert_false(transceiver.stopped);
-}, 'addTransceiver(\'audio\'): transceiver.stopped is false');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
- const transceiver = pc.addTransceiver('audio');
- const sender = pc.addTrack(track, stream);
- assert_equals(sender, transceiver.sender, 'sender == transceiver.sender');
- assert_equals(sender.track, track, 'sender.track == track');
-}, 'addTrack reuses reusable transceivers');
-
-promise_test(async t => {
- const pc = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
- const t1 = pc.addTransceiver('audio');
- const t2 = pc.addTransceiver(track);
- assert_not_equals(t2, t1, 't2 != t1');
- assert_equals(t2.sender.track, track, 't2.sender.track == track');
-}, 'addTransceiver does not reuse reusable transceivers');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t);
- const pc1Transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
- const pc2TrackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- const pc2Transceiver = pc2TrackEvent.transceiver;
- assert_equals(pc2Transceiver.direction, 'recvonly',
- 'pc2Transceiver.direction is recvonly after SRD(offer)');
- const pc2Sender = pc2.addTrack(track, stream);
- assert_equals(pc2Transceiver.sender, pc2Sender,
- 'pc2Transceiver.sender == sender');
- assert_equals(pc2Transceiver.direction, 'sendrecv',
- 'pc2Transceiver.direction is sendrecv after addTrack()');
- assert_equals(pc2Transceiver.currentDirection, null,
- 'pc2Transceiver.currentDirection is null before answer');
- const pc1TrackEvent = await exchangeAnswerAndListenToOntrack(t, pc1, pc2);
- assert_equals(pc2Transceiver.currentDirection, 'sendrecv',
- 'pc2Transceiver.currentDirection is sendrecv after SLD(answer)');
- assert_equals(pc1TrackEvent.transceiver, pc1Transceiver,
- 'Answer: pc1.ontrack fires with the existing transceiver.');
- assert_equals(pc1Transceiver.currentDirection, 'sendrecv',
- 'pc1Transceiver.currentDirection is sendrecv');
- assert_equals(pc2.getTransceivers().length, 1,
- 'pc2.getTransceivers().length == 1');
- assert_equals(pc1.getTransceivers().length, 1,
- 'pc1.getTransceivers().length == 1');
-}, 'Can setup two-way call using a single transceiver');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc2 = createPeerConnectionWithCleanup(t);
- const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
- const transceiver = pc1.addTransceiver(track);
- await exchangeOffer(pc1, pc2);
- await exchangeAnswer(pc1, pc2);
- assert_equals(transceiver.currentDirection, 'sendonly');
- assert_false(transceiver.stopped);
- pc1.close();
- assert_equals(transceiver.currentDirection, 'stopped');
- assert_true(transceiver.stopped);
-}, 'Closing the PC stops the transceivers');
-
-promise_test(async t => {
- const pc1 = createPeerConnectionWithCleanup(t);
- const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
- const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
- const pc2 = createPeerConnectionWithCleanup(t);
- exchangeIceCandidates(pc1, pc2);
-
- const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- await exchangeAnswer(pc1, pc2);
- localTransceiver.direction = 'inactive';
- await exchangeOfferAnswer(pc1, pc2);
-
- localTransceiver.direction = 'sendrecv';
- await exchangeOfferAndListenToOntrack(t, pc1, pc2);
-}, 'Changing transceiver direction to \'sendrecv\' makes ontrack fire');
-
-// Regression test coverage for https://crbug.com/950280.
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const pc2Promise = pc2.createOffer()
- .then((offer) => { return pc1.setRemoteDescription(offer); })
- .then(() => { return pc1.createAnswer(); })
- .then((answer) => { return pc1.setLocalDescription(answer); });
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const pc1Promise = pc1.createOffer()
- .then(() => { pc1.addTrack(pc1.getReceivers()[0].track); });
- await Promise.all([pc1Promise, pc2Promise]);
- assert_equals(pc1.getSenders()[0].track, pc1.getReceivers()[0].track);
-}, 'transceiver.sender.track does not revert to an old state');
-
-// Regression test coverage for https://crbug.com/950280.
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const pc2Promise = pc2.createOffer()
- .then((offer) => { return pc1.setRemoteDescription(offer); })
- .then(() => { return pc1.createAnswer(); });
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- const pc1Promise = pc1.createOffer()
- .then(() => { pc1.getTransceivers()[0].direction = 'inactive'; });
- await Promise.all([pc1Promise, pc2Promise]);
- assert_equals(pc1.getTransceivers()[0].direction, 'inactive');
-}, 'transceiver.direction does not revert to an old state');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection Video detector test</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// This test verifies that the helper function "detectSignal" from
-// RTCPeerConnectionHelper, which is used to detect changes in a video
-// signal, performs properly for a range of "signal" values.
-
-// If it fails, it indicates that the video codec used in this particular
-// browser at this time doesn't reproduce the luma signal reliably enough
-// for this particular application, which may lead to other tests that
-// use the "detectSignal" helper failing without an obvious cause.
-
-// The most likely failure is timeout - which will happen if the
-// luma value detected doesn't settle within the margin of error before
-// the test times out.
-
-async function signalSettlementTime(t, v, sender, signal, backgroundTrack) {
- const detectionStream = await getNoiseStream({video: {signal}});
- const [detectionTrack] = detectionStream.getTracks();
- try {
- await sender.replaceTrack(detectionTrack);
- const framesBefore = v.getVideoPlaybackQuality().totalVideoFrames;
- await detectSignal(t, v, signal);
- const framesAfter = v.getVideoPlaybackQuality().totalVideoFrames;
- await sender.replaceTrack(backgroundTrack);
- await detectSignal(t, v, 100);
- return framesAfter - framesBefore;
- } finally {
- detectionTrack.stop();
- }
-}
-
-promise_test(async t => {
- const v = document.createElement('video');
- v.autoplay = true;
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream1 = await getNoiseStream({video: {signal: 100}});
- const [track1] = stream1.getTracks();
- t.add_cleanup(() => track1.stop());
-
- const sender = pc1.addTrack(track1);
- const haveTrackEvent = new Promise(r => pc2.ontrack = r);
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- v.srcObject = new MediaStream([(await haveTrackEvent).track]);
- await new Promise(r => v.onloadedmetadata = r);
- // The basic signal is a track with signal 100. We replace this
- // with tracks with signal from 0 to 255 and see if they are all
- // reliably detected.
- await detectSignal(t, v, 100);
- // A few buffered frames are received with the old content, and a few
- // frames may not have settled on exactly the right value. In testing,
- // this test passes with maxFrames = 3; give a little more margin.
- const maxFrames = 7;
- // Test values 0 and 255
- let maxCount = await signalSettlementTime(t, v, sender, 0, track1);
- assert_less_than(maxCount, maxFrames,
- 'Should get the black value within ' + maxFrames + ' frames');
- maxCount = Math.max(
- await signalSettlementTime(t, v, sender, 255, track1), maxCount);
- assert_less_than(maxCount, maxFrames,
- 'Should get the white value within ' + maxFrames + ' frames');
- // Test a set of other values - far enough apart to make the test fast.
- for (let signal = 2; signal <= 255; signal += 47) {
- if (Math.abs(signal - 100) > 10) {
- const count = await signalSettlementTime(t, v, sender, signal, track1);
- maxCount = Math.max(count, maxCount);
- assert_less_than(maxCount, 10,
- 'Should get value ' + signal + ' within ' + maxFrames + ' frames');
- }
- }
- assert_less_than(maxCount, 10, 'Should get the right value within 10 frames');
-}, 'Signal detector detects track change within reasonable time');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<html>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-
-test(() => {
- init = {
- address: "168.3.4.5",
- port: 4711,
- url: "turn:turn.example.org",
- errorCode: 703,
- errorText: "Test error"
- };
- event = new RTCPeerConnectionIceErrorEvent('type', init);
- assert_equals(event.type, 'type');
- assert_equals(event.address, '168.3.4.5');
- assert_equals(event.port, 4711);
- assert_equals(event.url, "turn:turn.example.org");
- assert_equals(event.errorCode, 703);
- assert_equals(event.errorText, "Test error");
-}, 'RTCPeerConnectionIceErrorEvent constructed from init parameters');
-
-</script>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<!--
-4.8.2 RTCPeerConnectionIceEvent
-
- The icecandidate event of the RTCPeerConnection uses the RTCPeerConnectionIceEvent interface.
-
--->
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-/*
-RTCPeerConnectionIceEvent
-
-[Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict)]
-
-interface RTCPeerConnectionIceEvent : Event {
- readonly attribute RTCIceCandidate? candidate;
- readonly attribute DOMString? url;
-};
- */
-test(() => {
- assert_throws_js(TypeError, () => {
- new RTCPeerConnectionIceEvent();
- });
-}, "RTCPeerConnectionIceEvent with no arguments throws TypeError");
-
-test(() => {
- const event = new RTCPeerConnectionIceEvent("type", {
- candidate: null
- });
- assert_equals(event.candidate, null);
-}, "RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: null }");
-
-test(() => {
- const event = new RTCPeerConnectionIceEvent("type", {
- candidate: undefined
- });
- assert_equals(event.candidate, null);
-}, "RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: undefined }");
-
-
-/*
-
-4.8.1 RTCIceCandidate Interface
-
-The RTCIceCandidate() constructor takes a dictionary argument, candidateInitDict,
-whose content is used to initialize the new RTCIceCandidate object. When run, if
-both the sdpMid and sdpMLineIndex dictionary members are null, throw a TypeError.
-*/
-const candidate = "";
-const sdpMid = "sdpMid";
-const sdpMLineIndex = 1;
-const usernameFragment = "";
-const url = "foo.bar";
-
-test(() => {
- const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, usernameFragment });
- const event = new RTCPeerConnectionIceEvent("type", {
- candidate: iceCandidate,
- url,
- });
-
- assert_equals(event.candidate, iceCandidate);
- assert_false(event.bubbles);
- assert_false(event.cancelable);
-}, "RTCPeerConnectionIceEvent with RTCIceCandidate");
-
-test(() => {
- const plain = { candidate, sdpMid, sdpMLineIndex, usernameFragment };
- assert_throws_js(TypeError, () => new RTCPeerConnectionIceEvent("type", { candidate: plain }));
-}, "RTCPeerConnectionIceEvent with non RTCIceCandidate object throws");
-
-test(() => {
- const event = new RTCPeerConnectionIceEvent("type", {
- candidate: null,
- bubbles: true,
- cancelable: true,
- });
-
- assert_true(event.bubbles);
- assert_true(event.cancelable);
-}, "RTCPeerConnectionIceEvent bubbles and cancelable");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpParameters codecs</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // doOfferAnswerExchange
- // validateSenderRtpParameters
-
- /*
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- Promise<void> setParameters(optional RTCRtpParameters parameters);
- RTCRtpParameters getParameters();
- };
-
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- dictionary RTCRtpCodecParameters {
- [readonly]
- unsigned short payloadType;
-
- [readonly]
- DOMString mimeType;
-
- [readonly]
- unsigned long clockRate;
-
- [readonly]
- unsigned short channels;
-
- [readonly]
- DOMString sdpFmtpLine;
- };
-
- getParameters
- - The codecs sequence is populated based on the codecs that have been negotiated
- for sending, and which the user agent is currently capable of sending.
-
- If setParameters has removed or reordered codecs, getParameters MUST return
- the shortened/reordered list. However, every time codecs are renegotiated by
- a new offer/answer exchange, the list of codecs MUST be restored to the full
- negotiated set, in the priority order indicated by the remote description,
- in effect discarding the effects of setParameters.
-
- codecs
- - When using the setParameters method, the codecs sequence from the corresponding
- call to getParameters can be reordered and entries can be removed, but entries
- cannot be added, and the RTCRtpCodecParameters dictionary members cannot be modified.
- */
-
- // Get the first codec from param.codecs.
- // Assert that param.codecs has at least one element
- function getFirstCodec(param) {
- const { codecs } = param;
- assert_greater_than(codecs.length, 0);
- return codecs[0];
- }
-
- /*
- 5.2. setParameters
- 7. If parameters.encodings.length is different from N, or if any parameter
- in the parameters argument, marked as a Read-only parameter, has a value
- that is different from the corresponding parameter value returned from
- sender.getParameters(), abort these steps and return a promise rejected
- with a newly created InvalidModificationError. Note that this also applies
- to transactionId.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const codec = getFirstCodec(param);
-
- if(codec.payloadType === undefined) {
- codec.payloadType = 8;
- } else {
- codec.payloadType += 1;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with codec.payloadType modified should reject with InvalidModificationError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const codec = getFirstCodec(param);
-
- if(codec.mimeType === undefined) {
- codec.mimeType = 'audio/piedpiper';
- } else {
- codec.mimeType = `${codec.mimeType}-modified`;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with codec.mimeType modified should reject with InvalidModificationError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const codec = getFirstCodec(param);
-
- if(codec.clockRate === undefined) {
- codec.clockRate = 8000;
- } else {
- codec.clockRate += 1;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with codec.clockRate modified should reject with InvalidModificationError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const codec = getFirstCodec(param);
-
- if(codec.channels === undefined) {
- codec.channels = 6;
- } else {
- codec.channels += 1;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with codec.channels modified should reject with InvalidModificationError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const codec = getFirstCodec(param);
-
- if(codec.sdpFmtpLine === undefined) {
- codec.sdpFmtpLine = 'a=fmtp:98 0-15';
- } else {
- codec.sdpFmtpLine = `${codec.sdpFmtpLine};foo=1`;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const { codecs } = param;
-
- codecs.push({
- payloadType: 2,
- mimeType: 'audio/piedpiper',
- clockRate: 1000,
- channels: 2
- });
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, 'setParameters() with new codecs inserted should reject with InvalidModificationError');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpParameters encodings</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // validateSenderRtpParameters
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
- partial interface RTCPeerConnection {
- RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
- optional RTCRtpTransceiverInit init);
- ...
- };
-
- dictionary RTCRtpTransceiverInit {
- RTCRtpTransceiverDirection direction = "sendrecv";
- sequence<MediaStream> streams;
- sequence<RTCRtpEncodingParameters> sendEncodings;
- };
-
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- Promise<void> setParameters(optional RTCRtpParameters parameters);
- RTCRtpParameters getParameters();
- };
-
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- dictionary RTCRtpEncodingParameters {
- boolean active;
- unsigned long maxBitrate;
-
- [readonly]
- DOMString rid;
-
- double scaleResolutionDownBy;
- };
-
- getParameters
- - encodings is set to the value of the [[send encodings]] internal slot.
- */
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video');
-
- const param = transceiver.sender.getParameters();
- assert_equals(param.encodings.length, 1);
- // Do not call this in every test; it does not make sense to disable all of
- // the tests below for an implementation that is missing support for
- // fields that are not related to the test.
- validateSenderRtpParameters(param);
- }, `getParameters should return RTCRtpEncodingParameters with all required fields`);
-
- /*
- 5.1. addTransceiver
- 7. Create an RTCRtpSender with track, streams and sendEncodings and let sender
- be the result.
-
- 5.2. create an RTCRtpSender
- 5. Let sender have a [[send encodings]] internal slot, representing a list
- of RTCRtpEncodingParameters dictionaries.
- 6. If sendEncodings is given as input to this algorithm, and is non-empty,
- set the [[send encodings]] slot to sendEncodings.
-
- Otherwise, set it to a list containing a single RTCRtpEncodingParameters
- with active set to true.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 1);
- const encoding = param.encodings[0];
-
- assert_equals(encoding.active, true);
- assert_not_own_property(encoding, "maxBitrate");
- assert_not_own_property(encoding, "rid");
- assert_not_own_property(encoding, "scaleResolutionDownBy");
- // We do not check props from extension specifications here; those checks
- // need to go in a test-case for that extension specification.
- }, 'addTransceiver(audio) with undefined sendEncodings should have default encoding parameter with active set to true');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video');
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 1);
- const encoding = param.encodings[0];
-
- assert_equals(encoding.active, true);
- // spec says to return an encoding without a scaleResolutionDownBy value
- // when addTransceiver does not pass any encodings, however spec also says
- // to throw if setParameters is missing a scaleResolutionDownBy. One of
- // these two requirements needs to be removed, but it is unclear right now
- // which will be removed. For now, allow scaleResolutionDownBy, but don't
- // require it.
- // https://github.com/w3c/webrtc-pc/issues/2730
- assert_not_own_property(encoding, "maxBitrate");
- assert_not_own_property(encoding, "rid");
- assert_equals(encoding.scaleResolutionDownBy, undefined);
- // We do not check props from extension specifications here; those checks
- // need to go in a test-case for that extension specification.
- }, 'addTransceiver(video) with undefined sendEncodings should have default encoding parameter with active set to true and scaleResolutionDownBy set to 1');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio', { sendEncodings: [] });
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 1);
- const encoding = param.encodings[0];
-
- assert_equals(encoding.active, true);
- assert_not_own_property(encoding, "maxBitrate");
- assert_not_own_property(encoding, "rid");
- assert_not_own_property(encoding, "scaleResolutionDownBy");
- // We do not check props from extension specifications here; those checks
- // need to go in a test-case for that extension specification.
- }, 'addTransceiver(audio) with empty list sendEncodings should have default encoding parameter with active set to true');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video', { sendEncodings: [] });
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 1);
- const encoding = param.encodings[0];
-
- assert_equals(encoding.active, true);
- assert_not_own_property(encoding, "maxBitrate");
- assert_not_own_property(encoding, "rid");
- assert_equals(encoding.scaleResolutionDownBy, undefined);
- // We do not check props from extension specifications here; those checks
- // need to go in a test-case for that extension specification.
- }, 'addTransceiver(video) with empty list sendEncodings should have default encoding parameter with active set to true and scaleResolutionDownBy set to 1');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar", scaleResolutionDownBy: 3.0}]});
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 2);
- assert_equals(encodings[0].scaleResolutionDownBy, undefined);
- assert_equals(encodings[1].scaleResolutionDownBy, 3.0);
- }, `addTransceiver(video) should auto-set scaleResolutionDownBy to 1 when some encodings have it, but not all`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 2);
- assert_equals(encodings[0].scaleResolutionDownBy, undefined);
- assert_equals(encodings[1].scaleResolutionDownBy, undefined);
- }, `addTransceiver should auto-set scaleResolutionDownBy to powers of 2 (descending) when absent`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const sendEncodings = [];
- for (let i = 0; i < 1000; i++) {
- sendEncodings.push({rid: i});
- }
- const transceiver = pc.addTransceiver('video', {sendEncodings});
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_less_than(encodings.length, 1000, `1000 encodings is clearly too many`);
- }, `addTransceiver with a ridiculous number of encodings should truncate the list`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
-
- const param = transceiver.sender.getParameters();
- const { encodings } = param;
- assert_equals(encodings.length, 1);
- assert_not_own_property(encodings[0], "maxBitrate");
- assert_not_own_property(encodings[0], "rid");
- assert_not_own_property(encodings[0], "scaleResolutionDownBy");
- // We do not check props from extension specifications here; those checks
- // need to go in a test-case for that extension specification.
- }, `addTransceiver(audio) with multiple encodings should result in one encoding with no properties other than active`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {sender} = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo", scaleResolutionDownBy: 2.0}]});
- const {encodings} = sender.getParameters();
- assert_equals(encodings.length, 1);
- assert_not_own_property(encodings[0], "scaleResolutionDownBy");
- }, `addTransceiver(audio) should remove valid scaleResolutionDownBy`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {sender} = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo", scaleResolutionDownBy: -1.0}]});
- const {encodings} = sender.getParameters();
- assert_equals(encodings.length, 1);
- assert_not_own_property(encodings[0], "scaleResolutionDownBy");
- }, `addTransceiver(audio) should remove invalid scaleResolutionDownBy`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {sender} = pc.addTransceiver('audio');
- let params = sender.getParameters();
- assert_equals(params.encodings.length, 1);
- params.encodings[0].scaleResolutionDownBy = 2;
- await sender.setParameters(params);
- const {encodings} = sender.getParameters();
- assert_equals(encodings.length, 1);
- assert_not_own_property(encodings[0], "scaleResolutionDownBy");
- }, `setParameters with scaleResolutionDownBy on an audio sender should succeed, but remove the scaleResolutionDownBy`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {sender} = pc.addTransceiver('audio');
- let params = sender.getParameters();
- assert_equals(params.encodings.length, 1);
- params.encodings[0].scaleResolutionDownBy = -1;
- await sender.setParameters(params);
- const {encodings} = sender.getParameters();
- assert_equals(encodings.length, 1);
- assert_not_own_property(encodings[0], "scaleResolutionDownBy");
- }, `setParameters with an invalid scaleResolutionDownBy on an audio sender should succeed, but remove the scaleResolutionDownBy`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo"}, {rid: "foo"}] }));
- }, 'addTransceiver with duplicate rid and multiple encodings throws TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo"}, {}] }));
- }, 'addTransceiver with missing rid and multiple encodings throws TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: ""}] }));
- }, 'addTransceiver with empty rid throws TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "!?"}] }));
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "(âŊ°âĄÂ°)âŊïļĩ âŧââŧ"}] }));
- // RFC 8851 says '-' and '_' are allowed, but RFC 8852 says they are not.
- // RFC 8852 needs to be adhered to, otherwise we can't put the rid in RTP
- // https://github.com/w3c/webrtc-pc/issues/2732
- // https://www.rfc-editor.org/errata/eid7132
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo-bar"}] }));
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo_bar"}] }));
- }, 'addTransceiver with invalid rid characters throws TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- // https://github.com/w3c/webrtc-pc/issues/2732
- assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: 'a'.repeat(256)}] }));
- }, 'addTransceiver with rid longer than 255 characters throws TypeError');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: -1}] }));
- assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: 0}] }));
- assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: 0.5}] }));
- }, `addTransceiver with scaleResolutionDownBy < 1 throws RangeError`);
-
- /*
- 5.2. create an RTCRtpSender
- To create an RTCRtpSender with a MediaStreamTrack , track, a list of MediaStream
- objects, streams, and optionally a list of RTCRtpEncodingParameters objects,
- sendEncodings, run the following steps:
- 5. Let sender have a [[send encodings]] internal slot, representing a list
- of RTCRtpEncodingParameters dictionaries.
-
- 6. If sendEncodings is given as input to this algorithm, and is non-empty,
- set the [[send encodings]] slot to sendEncodings.
-
- 5.2. getParameters
- - encodings is set to the value of the [[send encodings]] internal slot.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video', {
- sendEncodings: [{
- active: false,
- maxBitrate: 8,
- rid: 'foo'
- }]
- });
-
- const param = sender.getParameters();
- const encoding = param.encodings[0];
-
- assert_equals(encoding.active, false);
- assert_equals(encoding.maxBitrate, 8);
- assert_not_own_property(encoding, "rid", "rid should be removed with a single encoding");
-
- }, `sender.getParameters() should return sendEncodings set by addTransceiver()`);
-
- /*
- 5.2. setParameters
- 3. Let N be the number of RTCRtpEncodingParameters stored in sender's internal
- [[send encodings]] slot.
- 7. If parameters.encodings.length is different from N, or if any parameter
- in the parameters argument, marked as a Read-only parameter, has a value
- that is different from the corresponding parameter value returned from
- sender.getParameters(), abort these steps and return a promise rejected
- with a newly created InvalidModificationError. Note that this also applies
- to transactionId.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video');
-
- const param = sender.getParameters();
-
- const { encodings } = param;
- assert_equals(encodings.length, 1);
-
- // While {} is valid RTCRtpEncodingParameters because all fields are
- // optional, it is still invalid to be missing a rid when there are multiple
- // encodings. Only trigger one kind of error here.
- encodings.push({ rid: "foo" });
- assert_equals(param.encodings.length, 2);
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `sender.setParameters() with added encodings should reject with InvalidModificationError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
-
- const param = sender.getParameters();
-
- const { encodings } = param;
- assert_equals(encodings.length, 2);
-
- encodings.pop();
- assert_equals(param.encodings.length, 1);
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `sender.setParameters() with removed encodings should reject with InvalidModificationError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
-
- const param = sender.getParameters();
-
- const { encodings } = param;
- assert_equals(encodings.length, 2);
- encodings.push(encodings.shift());
- assert_equals(param.encodings.length, 2);
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `sender.setParameters() with reordered encodings should reject with InvalidModificationError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video');
-
- const param = sender.getParameters();
-
- delete param.encodings;
-
- return promise_rejects_js(t, TypeError,
- sender.setParameters(param));
- }, `sender.setParameters() with encodings unset should reject with TypeError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video', {
- sendEncodings: [{ rid: 'foo' }, { rid: 'baz' }],
- });
-
- const param = sender.getParameters();
- const encoding = param.encodings[0];
-
- assert_equals(encoding.rid, 'foo');
-
- encoding.rid = 'bar';
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `setParameters() with modified encoding.rid field should reject with InvalidModificationError`);
-
- /*
- 5.2. setParameters
- 8. If the scaleResolutionDownBy parameter in the parameters argument has a
- value less than 1.0, abort these steps and return a promise rejected with
- a newly created RangeError.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video');
-
- const param = sender.getParameters();
- const encoding = param.encodings[0];
-
- encoding.scaleResolutionDownBy = 0.5;
- return promise_rejects_js(t, RangeError, sender.setParameters(param));
- encoding.scaleResolutionDownBy = 0;
- return promise_rejects_js(t, RangeError, sender.setParameters(param));
- encoding.scaleResolutionDownBy = -1;
- return promise_rejects_js(t, RangeError, sender.setParameters(param));
- }, `setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video');
-
- let param = sender.getParameters();
- const encoding = param.encodings[0];
-
- delete encoding.scaleResolutionDownBy;
- await sender.setParameters(param);
- param = sender.getParameters();
- assert_equals(param.encodings[0].scaleResolutionDownBy, undefined);
- }, `setParameters() with missing encoding.scaleResolutionDownBy field should succeed, and set the value back to 1`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('video');
-
- const param = sender.getParameters();
- const encoding = param.encodings[0];
-
- encoding.scaleResolutionDownBy = 1.5;
- return sender.setParameters(param)
- .then(() => {
- const param = sender.getParameters();
- const encoding = param.encodings[0];
-
- assert_approx_equals(encoding.scaleResolutionDownBy, 1.5, 0.01);
- });
- }, `setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed`);
-
- test_modified_encoding('video', 'active', false, true,
- 'setParameters() with encoding.active false->true should succeed (video)');
-
- test_modified_encoding('video', 'active', true, false,
- 'setParameters() with encoding.active true->false should succeed (video)');
-
- test_modified_encoding('video', 'maxBitrate', 10000, 20000,
- 'setParameters() with modified encoding.maxBitrate should succeed (video)');
-
- test_modified_encoding('audio', 'active', false, true,
- 'setParameters() with encoding.active false->true should succeed (audio)');
-
- test_modified_encoding('audio', 'active', true, false,
- 'setParameters() with encoding.active true->false should succeed (audio)');
-
- test_modified_encoding('audio', 'maxBitrate', 10000, 20000,
- 'setParameters() with modified encoding.maxBitrate should succeed (audio)');
-
- test_modified_encoding('video', 'scaleResolutionDownBy', 2, 4,
- 'setParameters() with modified encoding.scaleResolutionDownBy should succeed');
-
-</script>
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpParameters headerExtensions</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // validateSenderRtpParameters
-
- /*
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- Promise<void> setParameters(optional RTCRtpParameters parameters);
- RTCRtpParameters getParameters();
- };
-
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- dictionary RTCRtpHeaderExtensionParameters {
- [readonly]
- DOMString uri;
-
- [readonly]
- unsigned short id;
-
- [readonly]
- boolean encrypted;
- };
-
- getParameters
- - The headerExtensions sequence is populated based on the header extensions
- that have been negotiated for sending.
- */
-
- /*
- 5.2. setParameters
- 7. If parameters.encodings.length is different from N, or if any parameter
- in the parameters argument, marked as a Read-only parameter, has a value
- that is different from the corresponding parameter value returned from
- sender.getParameters(), abort these steps and return a promise rejected
- with a newly created InvalidModificationError. Note that this also applies
- to transactionId.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- param.headerExtensions = [{
- uri: 'non-existent.example.org',
- id: 404,
- encrypted: false
- }];
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `setParameters() with modified headerExtensions should reject with InvalidModificationError`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpParameters rtcp</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // validateSenderRtpParameters
-
- /*
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- Promise<void> setParameters(optional RTCRtpParameters parameters);
- RTCRtpParameters getParameters();
- };
-
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- dictionary RTCRtcpParameters {
- [readonly]
- DOMString cname;
-
- [readonly]
- boolean reducedSize;
- };
-
- getParameters
- - rtcp.cname is set to the CNAME of the associated RTCPeerConnection.
-
- rtcp.reducedSize is set to true if reduced-size RTCP has been negotiated for
- sending, and false otherwise.
- */
-
- /*
- 5.2. setParameters
- 7. If parameters.encodings.length is different from N, or if any parameter
- in the parameters argument, marked as a Read-only parameter, has a value
- that is different from the corresponding parameter value returned from
- sender.getParameters(), abort these steps and return a promise rejected
- with a newly created InvalidModificationError. Note that this also applies
- to transactionId.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const { rtcp } = param;
-
- if(rtcp === undefined) {
- param.rtcp = { cname: 'foo' };
-
- } else if(rtcp.cname === undefined) {
- rtcp.cname = 'foo';
-
- } else {
- rtcp.cname = `${rtcp.cname}-modified`;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `setParameters() with modified rtcp.cname should reject with InvalidModificationError`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const { rtcp } = param;
-
- if(rtcp === undefined) {
- param.rtcp = { reducedSize: true };
-
- } else if(rtcp.reducedSize === undefined) {
- rtcp.reducedSize = true;
-
- } else {
- rtcp.reducedSize = !rtcp.reducedSize;
- }
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpParameters transactionId</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // doOfferAnswerExchange
- // validateSenderRtpParameters
-
- /*
- 5.1. RTCPeerConnection Interface Extensions
- partial interface RTCPeerConnection {
- RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
- optional RTCRtpTransceiverInit init);
- ...
- };
-
- dictionary RTCRtpTransceiverInit {
- RTCRtpTransceiverDirection direction = "sendrecv";
- sequence<MediaStream> streams;
- sequence<RTCRtpEncodingParameters> sendEncodings;
- };
-
- addTransceiver
- 2. If the dictionary argument is present, and it has a sendEncodings member,
- let sendEncodings be that list of RTCRtpEncodingParameters objects, or an
- empty list otherwise.
- 7. Create an RTCRtpSender with track, streams and sendEncodings and let
- sender be the result.
-
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- Promise<void> setParameters(optional RTCRtpParameters parameters);
- RTCRtpParameters getParameters();
- };
-
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- getParameters
- - transactionId is set to a new unique identifier, used to match this
- getParameters call to a setParameters call that may occur later.
- */
-
- /*
- 5.2. getParameters
- - transactionId is set to a new unique identifier, used to match this
- getParameters call to a setParameters call that may occur later.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param1 = sender.getParameters();
- const param2 = sender.getParameters();
-
- validateSenderRtpParameters(param1);
- validateSenderRtpParameters(param2);
-
- assert_not_equals(param1.transactionId, param2.transactionId);
- }, `sender.getParameters() should return different transaction IDs for each call`);
-
- /*
- 5.2. setParameters
- 7. If parameters.encodings.length is different from N, or if any parameter
- in the parameters argument, marked as a Read-only parameter, has a value
- that is different from the corresponding parameter value returned from
- sender.getParameters(), abort these steps and return a promise rejected
- with a newly created InvalidModificationError. Note that this also applies
- to transactionId.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- const { transactionId } = param;
- param.transactionId = `${transactionId}-modified`;
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param));
- }, `sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- param.transactionId = undefined;
-
- return promise_rejects_js(t, TypeError,
- sender.setParameters(param));
- }, `sender.setParameters() with transaction ID unset should reject with TypeError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param = sender.getParameters();
- validateSenderRtpParameters(param);
-
- return sender.setParameters(param)
- .then(() =>
- promise_rejects_dom(t, 'InvalidStateError',
- sender.setParameters(param)));
- }, `setParameters() twice with the same parameters should reject with InvalidStateError`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const { sender } = pc.addTransceiver('audio');
- await doOfferAnswerExchange(t, pc);
-
- const param1 = sender.getParameters();
- const param2 = sender.getParameters();
-
- validateSenderRtpParameters(param1);
- validateSenderRtpParameters(param2);
-
- assert_not_equals(param1.transactionId, param2.transactionId);
-
- return promise_rejects_dom(t, 'InvalidModificationError',
- sender.setParameters(param1));
- }, `setParameters() with parameters older than last getParameters() should reject with InvalidModificationError`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpReceiver.getCapabilities</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpCapabilities-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 RTCRtpCapabilities-helper.js:
- // validateRtpCapabilities
-
- /*
- 5.3. RTCRtpReceiver Interface
- interface RTCRtpReceiver {
- ...
- static RTCRtpCapabilities getCapabilities(DOMString kind);
- };
- */
- test(() => {
- const capabilities = RTCRtpReceiver.getCapabilities('audio');
- validateRtpCapabilities(capabilities);
- }, `RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary`);
-
- test(() => {
- const capabilities = RTCRtpReceiver.getCapabilities('video');
- validateRtpCapabilities(capabilities);
- }, `RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary`);
-
- test(() => {
- const capabilities = RTCRtpReceiver.getCapabilities('dummy');
- assert_equals(capabilities, null);
- }, `RTCRtpSender.getCapabilities('dummy') should return null`);
-
- </script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpReceiver.prototype.getContributingSources</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-async function connectAndExpectNoCsrcs(t, kind) {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({[kind]:true});
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
- pc1.addTrack(track, stream);
-
- exchangeIceCandidates(pc1, pc2);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- await exchangeAnswer(pc1, pc2);
-
- assert_array_equals(trackEvent.receiver.getContributingSources(), []);
-}
-
-promise_test(async t => {
- await connectAndExpectNoCsrcs(t, 'audio');
-}, '[audio] getContributingSources() returns an empty list in loopback call');
-
-promise_test(async t => {
- await connectAndExpectNoCsrcs(t, 'video');
-}, '[video] getContributingSources() returns an empty list in loopback call');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpReceiver.prototype.getParameters</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
- // validateReceiverRtpParameters
-
- /*
- Validates the RTCRtpParameters returned from RTCRtpReceiver.prototype.getParameters
-
- 5.3. RTCRtpReceiver Interface
- getParameters
- When getParameters is called, the RTCRtpParameters dictionary is constructed
- as follows:
-
- - The headerExtensions sequence is populated based on the header extensions that
- the receiver is currently prepared to receive.
-
- - The codecs sequence is populated based on the codecs that the receiver is currently
- prepared to receive.
-
- - rtcp.reducedSize is set to true if the receiver is currently prepared to receive
- reduced-size RTCP packets, and false otherwise. rtcp.cname is left undefined.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('audio');
- const callee = await doOfferAnswerExchange(t, pc);
- const param = callee.getTransceivers()[0].receiver.getParameters();
- validateReceiverRtpParameters(param);
-
- assert_greater_than(param.headerExtensions.length, 0);
- assert_greater_than(param.codecs.length, 0);
- }, 'getParameters() with audio receiver');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver('video');
- const callee = await doOfferAnswerExchange(t, pc);
- const param = callee.getTransceivers()[0].receiver.getParameters();
- validateReceiverRtpParameters(param);
-
- assert_greater_than(param.headerExtensions.length, 0);
- assert_greater_than(param.codecs.length, 0);
- }, 'getParameters() with video receiver');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title></title>
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // A generous testing duration that will not time out on bots.
- const kEncodeDurationMs = 10000;
-
- // The crash this test aims to repro was easy to reproduce using a normal
- // getUserMedia() track when running the browser normally, e.g. by navigating
- // to https://jsfiddle.net/henbos/fc7gk3ve/11/. But for some reason, the fake
- // tracks returned by getUserMedia() when inside this testing environment had
- // a much harder time with reproducibility.
- //
- // By creating a high FPS canvas capture track we are able to repro reliably
- // in this WPT environment as well.
- function whiteNoise(width, height) {
- const canvas =
- Object.assign(document.createElement('canvas'), {width, height});
- const ctx = canvas.getContext('2d');
- ctx.fillRect(0, 0, width, height);
- const p = ctx.getImageData(0, 0, width, height);
- requestAnimationFrame(function draw () {
- for (let i = 0; i < p.data.length; i++) {
- const color = Math.random() * 255;
- p.data[i++] = color;
- p.data[i++] = color;
- p.data[i++] = color;
- }
- ctx.putImageData(p, 0, 0);
- requestAnimationFrame(draw);
- });
- return canvas.captureStream();
- }
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = whiteNoise(640, 480);
- const [track] = stream.getTracks();
- const t1 = pc1.addTransceiver("video", {direction:"sendonly"});
- const t2 = pc1.addTransceiver("video", {direction:"sendonly"});
- await t1.sender.replaceTrack(track);
- await t2.sender.replaceTrack(track);
-
- exchangeIceCandidates(pc1, pc2);
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-
- // In Chromium, each sender instantiates a VideoStreamEncoder during
- // negotiation. This test reproduces https://crbug.com/webrtc/11485 where a
- // race causes a crash when multiple VideoStreamEncoders are encoding the
- // same MediaStreamTrack.
- await new Promise(resolve => t.step_timeout(resolve, kEncodeDurationMs));
- }, "Two RTCRtpSenders encoding the same track");
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpSender.getCapabilities</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCRtpCapabilities-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 RTCRtpCapabilities-helper.js:
- // validateRtpCapabilities
-
- /*
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- ...
- static RTCRtpCapabilities getCapabilities(DOMString kind);
- };
-
- getCapabilities
- The getCapabilities() method returns the most optimist view on the capabilities
- of the system for sending media of the given kind. It does not reserve any
- resources, ports, or other state but is meant to provide a way to discover
- the types of capabilities of the browser including which codecs may be supported.
- */
- test(() => {
- const capabilities = RTCRtpSender.getCapabilities('audio');
- validateRtpCapabilities(capabilities);
- }, `RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary`);
-
- test(() => {
- const capabilities = RTCRtpSender.getCapabilities('video');
- validateRtpCapabilities(capabilities);
- }, `RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary`);
-
- test(() => {
- const capabilities = RTCRtpSender.getCapabilities('dummy');
- assert_equals(capabilities, null);
- }, `RTCRtpSender.getCapabilities('dummy') should return null`);
-
- </script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCRtpSender.prototype.replaceTrack</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/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
-
- /*
- 5.2. RTCRtpSender Interface
- interface RTCRtpSender {
- readonly attribute MediaStreamTrack? track;
- Promise<void> replaceTrack(MediaStreamTrack? withTrack);
- ...
- };
-
- replaceTrack
- Attempts to replace the track being sent with another track provided
- (or with a null track), without renegotiation.
- */
-
- /*
- 5.2. replaceTrack
- 4. If connection's [[isClosed]] slot is true, return a promise rejected
- with a newly created InvalidStateError and abort these steps.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const transceiver = pc.addTransceiver('audio');
- const { sender } = transceiver;
- pc.close();
-
- return promise_rejects_dom(t, 'InvalidStateError',
- sender.replaceTrack(track));
- }, 'Calling replaceTrack on closed connection should reject with InvalidStateError');
-
- /*
- 5.2. replaceTrack
- 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.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const transceiver = pc.addTransceiver('audio');
- const { sender } = transceiver;
- assert_equals(sender.track, null);
-
- return sender.replaceTrack(track)
- .then(() => {
- assert_equals(sender.track, track);
- });
- }, 'Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- const [track1] = stream1.getTracks();
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- const [track2] = stream2.getTracks();
-
- const transceiver = pc.addTransceiver(track1);
- const { sender } = transceiver;
-
- assert_equals(sender.track, track1);
-
- return sender.replaceTrack(track2)
- .then(() => {
- assert_equals(sender.track, track2);
- });
- }, 'Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
-
- return sender.replaceTrack(null)
- .then(() => {
- assert_equals(sender.track, null);
- });
- }, 'Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null');
-
- /*
- 5.2. replaceTrack
- 10. Run the following steps in parallel:
- 1. Determine if negotiation is needed to transmit withTrack in place
- of the sender's existing track.
-
- Negotiation is not needed if withTrack is null.
-
- 3. Queue a task that runs the following steps:
- 2. Set sender's track attribute to withTrack.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const transceiver = pc.addTransceiver(track);
- const { sender } = transceiver;
-
- assert_equals(sender.track, track);
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => sender.replaceTrack(null))
- .then(() => {
- assert_equals(sender.track, null);
- });
- }, 'Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null');
-
- /*
- 5.2. replaceTrack
- 10. Run the following steps in parallel:
- 1. Determine if negotiation is needed to transmit withTrack in place
- of the sender's existing track.
-
- Negotiation is not needed if the sender's existing track is
- ended (which appears as though the track was muted).
-
- 3. Queue a task that runs the following steps:
- 2. Set sender's track attribute to withTrack.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- const [track1] = stream1.getTracks();
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- const [track2] = stream1.getTracks();
-
- const transceiver = pc.addTransceiver(track1);
- const { sender } = transceiver;
- assert_equals(sender.track, track1);
-
- track1.stop();
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => sender.replaceTrack(track2))
- .then(() => {
- assert_equals(sender.track, track2);
- });
- }, 'Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track');
-
- /*
- 5.2. replaceTrack
- 10. Run the following steps in parallel:
- 1. Determine if negotiation is needed to transmit withTrack in place
- of the sender's existing track.
-
- (tracks generated with default parameters *should* be similar
- enough to not require re-negotiation)
-
- 3. Queue a task that runs the following steps:
- 2. Set sender's track attribute to withTrack.
- */
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- const [track1] = stream1.getTracks();
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- const [track2] = stream1.getTracks();
-
- const transceiver = pc.addTransceiver(track1);
- const { sender } = transceiver;
- assert_equals(sender.track, track1);
-
- return pc.createOffer()
- .then(offer => pc.setLocalDescription(offer))
- .then(() => sender.replaceTrack(track2))
- .then(() => {
- assert_equals(sender.track, track2);
- });
- }, 'Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track');
-
- /*
- TODO
- 5.2. replaceTrack
- To avoid track identifiers changing on the remote receiving end when
- a track is replaced, the sender must retain the original track
- identifier and stream associations and use these in subsequent
- negotiations.
-
- Non-Testable
- 5.2. replaceTrack
- 10. Run the following steps in parallel:
- 1. Determine if negotiation is needed to transmit withTrack in place
- of the sender's existing track.
-
- Ignore which MediaStream the track resides in and the id attribute
- of the track in this determination.
-
- If negotiation is needed, then reject p with a newly created
- InvalidModificationError and abort these steps.
-
- 2. If withTrack is null, have the sender stop sending, without
- 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.
- */
-
-promise_test(async t => {
- const v = document.createElement('video');
- v.autoplay = true;
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const stream1 = await getNoiseStream({video: {signal: 20}});
- t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
- const [track1] = stream1.getTracks();
- const stream2 = await getNoiseStream({video: {signal: 250}});
- t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
- const [track2] = stream2.getTracks();
- const sender = pc1.addTrack(track1);
- pc2.ontrack = (e) => {
- v.srcObject = new MediaStream([e.track]);
- };
- const metadataToBeLoaded = new Promise((resolve) => {
- v.addEventListener('loadedmetadata', () => {
- resolve();
- });
- });
- exchangeIceCandidates(pc1, pc2);
- exchangeOfferAnswer(pc1, pc2);
- await metadataToBeLoaded;
- await detectSignal(t, v, 20);
- await sender.replaceTrack(track2);
- await detectSignal(t, v, 250);
-}, 'ReplaceTrack transmits the new track not the old track');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpSender.prototype.setParameters</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- /*
- 5.2. setParameters
- 6. If transceiver.stopped is true, abort these steps and return a promise
- rejected with a newly created InvalidStateError.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const { sender } = transceiver;
-
- const param = sender.getParameters();
- transceiver.stop();
-
- return promise_rejects_dom(t, 'InvalidStateError',
- sender.setParameters(param));
- }, `setParameters() when transceiver is stopped should reject with InvalidStateError`);
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpSender.prototype.setStreams</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const sender = caller.addTrack(track);
- const stream1 = new MediaStream();
- const stream2 = new MediaStream();
- sender.setStreams(stream1, stream2);
-
- const offer = await caller.createOffer();
- callee.setRemoteDescription(offer);
- return new Promise(resolve => callee.ontrack = t.step_func(event =>{
- assert_equals(event.streams.length, 2);
- const calleeStreamIds = event.streams.map(s => s.id);
- assert_in_array(stream1.id, calleeStreamIds);
- assert_in_array(stream2.id, calleeStreamIds);
- resolve();
- }));
-}, 'setStreams causes streams to be reported via ontrack on callee');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
-
- const sender = caller.addTrack(track);
- sender.setStreams(stream);
-
- const offer = await caller.createOffer();
- callee.setRemoteDescription(offer);
- return new Promise(resolve => callee.ontrack = t.step_func(event =>{
- assert_equals(event.streams.length, 1);
- assert_equals(stream.id, event.streams[0].id);
- assert_equals(track.id, event.track.id);
- assert_equals(event.streams[0].getTracks()[0], event.track);
- resolve();
- }));
-}, 'setStreams can be used to reconstruct a stream with a track on the remote side');
-
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- callee.ontrack = t.unreached_func();
- const transceiver = caller.addTransceiver('audio', {direction: 'inactive'});
- await exchangeOfferAnswer(caller, callee);
-
- const stream1 = new MediaStream();
- const stream2 = new MediaStream();
- transceiver.direction = 'sendrecv';
- transceiver.sender.setStreams(stream1, stream2);
-
- const offer = await caller.createOffer();
- callee.setRemoteDescription(offer);
- return new Promise(resolve => callee.ontrack = t.step_func(event =>{
- assert_equals(event.streams.length, 2);
- const calleeStreamIds = event.streams.map(s => s.id);
- assert_in_array(stream1.id, calleeStreamIds);
- assert_in_array(stream2.id, calleeStreamIds);
- assert_in_array(event.track, event.streams[0].getTracks());
- assert_in_array(event.track, event.streams[1].getTracks());
- resolve();
- }));
-}, 'Adding streams and changing direction causes new streams to be reported via ontrack on callee');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
-
- const stream1 = new MediaStream();
- const stream2 = new MediaStream();
- let calleeTrack = null;
- callee.ontrack = t.step_func(event => {
- assert_equals(event.streams.length, 0);
- calleeTrack = event.track;
- });
- const transceiver = caller.addTransceiver('audio', {direction: 'sendrecv'});
- await exchangeOfferAnswer(caller, callee);
- assert_true(calleeTrack instanceof MediaStreamTrack);
-
- transceiver.sender.setStreams(stream1, stream2);
- const offer = await caller.createOffer();
- callee.setRemoteDescription(offer);
- return new Promise(resolve => callee.ontrack = t.step_func(event =>{
- assert_equals(event.streams.length, 2);
- const calleeStreamIds = event.streams.map(s => s.id);
- assert_in_array(stream1.id, calleeStreamIds);
- assert_in_array(stream2.id, calleeStreamIds);
- assert_in_array(event.track, event.streams[0].getTracks());
- assert_in_array(event.track, event.streams[1].getTracks());
- assert_equals(event.track, calleeTrack);
- resolve();
- }));
-}, 'Adding streams to an active transceiver causes new streams to be reported via ontrack on callee');
-
-test(t => {
- const pc = new RTCPeerConnection();
- const stream1 = new MediaStream();
- const stream2 = new MediaStream();
- const transceiver = pc.addTransceiver('audio');
-
- pc.close();
- assert_throws_dom('InvalidStateError', () => transceiver.sender.setStreams(stream1, stream2));
-}, 'setStreams() fires InvalidStateError on a closed peer connection.');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCRtpSender.transport</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/dictionary-helper.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // Spec link: http://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-transport
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = caller.addTrack(track);
- assert_equals(sender.transport, null);
- }, 'RTCRtpSender.transport is null when unconnected');
-
- // Test for the simple/happy path of connecting a single track
- promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track] = stream.getTracks();
- const sender = caller.addTrack(track);
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- exchangeIceCandidates(caller, callee);
- await exchangeOfferAndListenToOntrack(t, caller, callee);
- assert_not_equals(sender.transport, null);
- const [transceiver] = caller.getTransceivers();
- assert_equals(transceiver.sender.transport,
- transceiver.receiver.transport);
- assert_not_equals(sender.transport.iceTransport, null);
- }, 'RTCRtpSender/receiver.transport has a value when connected');
-
- // Test with multiple tracks, and checking details of when things show up
- // for different bundle policies.
- for (let bundle_policy of ['balanced', 'max-bundle', 'max-compat']) {
- promise_test(async t => {
- const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
- t.add_cleanup(() => caller.close());
- const stream = await getNoiseStream(
- {audio: true, video:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track1, track2] = stream.getTracks();
- const sender1 = caller.addTrack(track1);
- const sender2 = caller.addTrack(track2);
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- exchangeIceCandidates(caller, callee);
- const offer = await caller.createOffer();
- assert_equals(sender1.transport, null);
- assert_equals(sender2.transport, null);
- await caller.setLocalDescription(offer);
- assert_not_equals(sender1.transport, null);
- assert_not_equals(sender2.transport, null);
- const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
- assert_equals(sender1.transport, caller_transceiver1.sender.transport);
- if (bundle_policy == 'max-bundle') {
- assert_equals(caller_transceiver1.sender.transport,
- caller_transceiver2.sender.transport);
- } else {
- assert_not_equals(caller_transceiver1.sender.transport,
- caller_transceiver2.sender.transport);
- }
- await callee.setRemoteDescription(offer);
- const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
- // According to spec, setRemoteDescription only updates the transports
- // if the remote description is an answer.
- assert_equals(callee_transceiver1.receiver.transport, null);
- assert_equals(callee_transceiver2.receiver.transport, null);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- assert_not_equals(callee_transceiver1.receiver.transport, null);
- assert_not_equals(callee_transceiver2.receiver.transport, null);
- // At this point, bundle should have kicked in.
- assert_equals(callee_transceiver1.receiver.transport,
- callee_transceiver2.receiver.transport);
- await caller.setRemoteDescription(answer);
- assert_equals(caller_transceiver1.receiver.transport,
- caller_transceiver2.receiver.transport);
- }, 'RTCRtpSender/receiver.transport at the right time, with bundle policy ' + bundle_policy);
-
- // Do the same test again, with DataChannel in the mix.
- promise_test(async t => {
- const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
- t.add_cleanup(() => caller.close());
- const stream = await getNoiseStream(
- {audio: true, video:true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const [track1, track2] = stream.getTracks();
- const sender1 = caller.addTrack(track1);
- const sender2 = caller.addTrack(track2);
- caller.createDataChannel('datachannel');
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- exchangeIceCandidates(caller, callee);
- const offer = await caller.createOffer();
- assert_equals(sender1.transport, null);
- assert_equals(sender2.transport, null);
- if (caller.sctp) {
- assert_equals(caller.sctp.transport, null);
- }
- await caller.setLocalDescription(offer);
- assert_not_equals(sender1.transport, null);
- assert_not_equals(sender2.transport, null);
- assert_not_equals(caller.sctp.transport, null);
- const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
- assert_equals(sender1.transport, caller_transceiver1.sender.transport);
- if (bundle_policy == 'max-bundle') {
- assert_equals(caller_transceiver1.sender.transport,
- caller_transceiver2.sender.transport);
- assert_equals(caller_transceiver1.sender.transport,
- caller.sctp.transport);
- } else {
- assert_not_equals(caller_transceiver1.sender.transport,
- caller_transceiver2.sender.transport);
- assert_not_equals(caller_transceiver1.sender.transport,
- caller.sctp.transport);
- }
- await callee.setRemoteDescription(offer);
- const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
- // According to spec, setRemoteDescription only updates the transports
- // if the remote description is an answer.
- assert_equals(callee_transceiver1.receiver.transport, null);
- assert_equals(callee_transceiver2.receiver.transport, null);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- assert_not_equals(callee_transceiver1.receiver.transport, null);
- assert_not_equals(callee_transceiver2.receiver.transport, null);
- assert_not_equals(callee.sctp.transport, null);
- // At this point, bundle should have kicked in.
- assert_equals(callee_transceiver1.receiver.transport,
- callee_transceiver2.receiver.transport);
- assert_equals(callee_transceiver1.receiver.transport,
- callee.sctp.transport,
- 'Callee SCTP transport does not match:');
- await caller.setRemoteDescription(answer);
- assert_equals(caller_transceiver1.receiver.transport,
- caller_transceiver2.receiver.transport);
- assert_equals(caller_transceiver1.receiver.transport,
- caller.sctp.transport,
- 'Caller SCTP transport does not match:');
- }, 'RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy ' + bundle_policy);
- }
- </script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpSender</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
-test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const t1 = pc.addTransceiver("audio");
- const t2 = pc.addTransceiver("video");
-
- assert_not_equals(t1.sender.dtmf, null);
- assert_equals(t2.sender.dtmf, null);
-}, "Video sender @dtmf is null");
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpTransceiver.prototype.direction</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://rawgit.com/w3c/webrtc-pc/8495678808d126d8bc764bf944996f32981fa6fd/webrtc.html
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // generateAnswer
-
- /*
- 5.4. RTCRtpTransceiver Interface
- interface RTCRtpTransceiver {
- attribute RTCRtpTransceiverDirection direction;
- readonly attribute RTCRtpTransceiverDirection? currentDirection;
- ...
- };
- */
-
- /*
- 5.4. direction
- 7. Set transceiver's [[Direction]] slot to newDirection.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- assert_equals(transceiver.direction, 'sendrecv');
- assert_equals(transceiver.currentDirection, null);
-
- transceiver.direction = 'recvonly';
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, null,
- 'Expect transceiver.currentDirection to not change');
-
- }, 'setting direction should change transceiver.direction');
-
- /*
- 5.4. direction
- 3. If newDirection is equal to transceiver's [[Direction]] slot, abort
- these steps.
- */
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' });
- assert_equals(transceiver.direction, 'sendonly');
- transceiver.direction = 'sendonly';
- assert_equals(transceiver.direction, 'sendonly');
-
- }, 'setting direction with same direction should have no effect');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio', { direction: 'recvonly' });
- assert_equals(transceiver.direction, 'recvonly');
- assert_equals(transceiver.currentDirection, null);
-
- return pc.createOffer()
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer)))
- .then(answer => pc.setRemoteDescription(answer))
- .then(() => {
- assert_equals(transceiver.currentDirection, 'inactive');
- transceiver.direction = 'sendrecv';
- assert_equals(transceiver.direction, 'sendrecv');
- assert_equals(transceiver.currentDirection, 'inactive');
- });
- }, 'setting direction should change transceiver.direction independent of transceiver.currentDirection');
-
- /*
- TODO
- An update of directionality does not take effect immediately. Instead, future calls
- to createOffer and createAnswer mark the corresponding media description as
- sendrecv, sendonly, recvonly or inactive as defined in [JSEP] (section 5.2.2.
- and section 5.3.2.).
-
- Tested in RTCPeerConnection-onnegotiationneeded.html
- 5.4. direction
- 6. Update the negotiation-needed flag for connection.
-
- Coverage Report
- Tested 6
- Not Tested 1
- Untestable 0
- Total 7
- */
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpTransceiver.prototype.setCodecPreferences</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="./third_party/sdp/sdp.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- /*
- 5.4. RTCRtpTransceiver Interface
- interface RTCRtpTransceiver {
- ...
- void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
- };
-
- setCodecPreferences
- - Setting codecs to an empty sequence resets codec preferences to any
- default value.
-
- - The codecs sequence passed into setCodecPreferences can only contain
- codecs that are returned by RTCRtpSender.getCapabilities(kind) or
- RTCRtpReceiver.getCapabilities(kind), where kind is the kind of the
- RTCRtpTransceiver on which the method is called. Additionally, the
- RTCRtpCodecParameters dictionary members cannot be modified. If
- codecs does not fulfill these requirements, the user agent MUST throw
- an InvalidModificationError.
- */
- /*
- * Chromium note: this requires build bots with H264 support. See
- * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
- * for details on how to enable support.
- */
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- transceiver.setCodecPreferences(capabilities.codecs);
- }, `setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video');
- const capabilities = RTCRtpReceiver.getCapabilities('video');
- transceiver.setCodecPreferences(capabilities.codecs);
- }, `setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities1 = RTCRtpSender.getCapabilities('audio');
- const capabilities2 = RTCRtpReceiver.getCapabilities('audio');
- transceiver.setCodecPreferences([...capabilities1.codecs, ... capabilities2.codecs]);
- }, `setCodecPreferences() with both sender receiver codecs combined should succeed`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- transceiver.setCodecPreferences([]);
- }, `setCodecPreferences([]) should succeed`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- const { codecs } = capabilities;
-
- if(codecs.length >= 2) {
- const tmp = codecs[0];
- codecs[0] = codecs[1];
- codecs[1] = tmp;
- }
-
- transceiver.setCodecPreferences(codecs);
- }, `setCodecPreferences() with reordered codecs should succeed`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('video');
- const capabilities = RTCRtpSender.getCapabilities('video');
- const { codecs } = capabilities;
- // This test verifies that the mandatory VP8 codec is present
- // and can be set.
- let tried = false;
- codecs.forEach(codec => {
- if (codec.mimeType.toLowerCase() === 'video/vp8') {
- transceiver.setCodecPreferences([codecs[0]]);
- tried = true;
- }
- });
- assert_true(tried, 'VP8 video codec was found and tried');
- }, `setCodecPreferences() with only VP8 should succeed`);
-
- test(() => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('video');
- const capabilities = RTCRtpSender.getCapabilities('video');
- const { codecs } = capabilities;
- // This test verifies that the mandatory H264 codec is present
- // and can be set.
- let tried = false;
- codecs.forEach(codec => {
- if (codec.mimeType.toLowerCase() === 'video/h264') {
- transceiver.setCodecPreferences([codecs[0]]);
- tried = true;
- }
- });
- assert_true(tried, 'H264 video codec was found and tried');
- }, `setCodecPreferences() with only H264 should succeed`);
-
- async function getRTPMapLinesWithCodecAsFirst(firstCodec)
- {
- const capabilities = RTCRtpSender.getCapabilities('video').codecs;
- capabilities.forEach((codec, idx) => {
- if (codec.mimeType === firstCodec) {
- capabilities.splice(idx, 1);
- capabilities.unshift(codec);
- }
- });
-
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('video');
- transceiver.setCodecPreferences(capabilities);
- const offer = await pc.createOffer();
-
- return offer.sdp.split('\r\n').filter(line => line.indexOf("a=rtpmap") === 0);
- }
-
- promise_test(async () => {
- const lines = await getRTPMapLinesWithCodecAsFirst('video/VP8');
-
- assert_greater_than(lines.length, 1);
- assert_true(lines[0].indexOf("VP8") !== -1, "VP8 should be the first codec");
- }, `setCodecPreferences() should allow setting VP8 as first codec`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('video');
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(capabilities.codecs));
- }, `setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const codecs = [{
- mimeType: 'data',
- clockRate: 2000,
- channels: 2,
- sdpFmtpLine: '0-15'
- }];
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const codecs = [{
- mimeType: 'audio/piepiper',
- clockRate: 2000,
- channels: 2,
- sdpFmtpLine: '0-15'
- }];
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with user defined codec should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- const codecs = [
- ...capabilities.codecs,
- {
- mimeType: 'audio/piepiper',
- clockRate: 2000,
- channels: 2,
- sdpFmtpLine: '0-15'
- }];
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- const codecs = [capabilities.codecs[0]];
- codecs[0].clockRate = codecs[0].clockRate / 2;
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with modified codec clock rate should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- const codecs = [capabilities.codecs[0]];
- codecs[0].channels = codecs[0].channels + 11;
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with modified codec channel count should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
- const codecs = [capabilities.codecs[0]];
- codecs[0].sdpFmtpLine = "modifiedparameter=1";
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with modified codec parameters should throw InvalidModificationError`);
-
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const capabilities = RTCRtpSender.getCapabilities('audio');
-
- const { codecs } = capabilities;
- assert_greater_than(codecs.length, 0,
- 'Expect at least one codec available');
-
- const [ codec ] = codecs;
- const { channels=2 } = codec;
- codec.channels = channels+1;
-
- assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
- }, `setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError`);
-
- promise_test(async (t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const transceiver = pc.addTransceiver('audio');
- const {codecs} = RTCRtpSender.getCapabilities('audio');
- // Reorder codecs, put PCMU/PCMA first.
- let firstCodec;
- let i;
- for (i = 0; i < codecs.length; i++) {
- const codec = codecs[i];
- if (codec.mimeType === 'audio/PCMU' || codec.mimeType === 'audio/PCMA') {
- codecs.splice(i, 1);
- codecs.unshift(codec);
- firstCodec = codec.mimeType.substr(6);
- break;
- }
- }
- assert_not_equals(firstCodec, undefined, 'PCMU or PCMA codec not found');
- transceiver.setCodecPreferences(codecs);
-
- const offer = await pc.createOffer();
- const mediaSection = SDPUtils.getMediaSections(offer.sdp)[0];
- const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
- assert_equals(rtpParameters.codecs[0].name, firstCodec);
- }, `setCodecPreferences() modifies the order of audio codecs in createOffer`);
-
- </script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpTransceiver.prototype.stop</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-// FIXME: Add a test adding a transceiver, stopping it and trying to create an empty offer.
-
-promise_test(async (t)=> {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- pc1.addTransceiver("audio", { direction: "sendonly" });
- pc1.addTransceiver("video");
- pc1.getTransceivers()[0].stop();
-
- const offer = await pc1.createOffer();
-
- assert_false(offer.sdp.includes("m=audio"), "offer should not contain an audio m-section");
- assert_true(offer.sdp.includes("m=video"), "offer should contain a video m-section");
-}, "A transceiver added and stopped before the initial offer generation should not trigger an offer m-section generation");
-
-promise_test(async (t)=> {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- pc1.addTransceiver("audio", { direction: "sendonly" });
- pc1.addTransceiver("video");
- assert_equals(null, pc1.getTransceivers()[1].receiver.transport);
-
- pc1.getTransceivers()[1].stop();
- assert_equals(pc1.getTransceivers()[1].receiver.transport, null);
-}, "A transceiver added and stopped should not crash when getting receiver's transport");
-
-promise_test(async (t)=> {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
-
- await exchangeOfferAnswer(pc1, pc2);
-
- pc1.addTransceiver("video");
-
- pc1.getTransceivers()[0].stop();
- pc1.getTransceivers()[1].stop();
-
- const offer = await pc1.createOffer();
-
- assert_true(offer.sdp.includes("m=audio"), "offer should contain an audio m-section");
- assert_true(offer.sdp.includes("m=audio 0"), "The audio m-section should be rejected");
-
- assert_false(offer.sdp.includes("m=video"), "offer should not contain a video m-section");
-}, "During renegotiation, adding and stopping a transceiver should not trigger a renegotiated offer m-section generation");
-
-promise_test(async (t)=> {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
-
- await exchangeOfferAnswer(pc1, pc2);
-
- pc1.getTransceivers()[0].direction = "sendonly";
- pc1.getTransceivers()[0].stop();
-
- const offer = await pc1.createOffer();
-
- assert_true(offer.sdp.includes("a=inactive"), "The audio m-section should be inactive");
-}, "A stopped sendonly transceiver should generate an inactive m-section in the offer");
-
-promise_test(async (t)=> {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
-
- await exchangeOfferAnswer(pc1, pc2);
-
- pc1.getTransceivers()[0].direction = "inactive";
- pc1.getTransceivers()[0].stop();
-
- const offer = await pc1.createOffer();
-
- assert_true(offer.sdp.includes("a=inactive"), "The audio m-section should be inactive");
-}, "A stopped inactive transceiver should generate an inactive m-section in the offer");
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
- await exchangeOfferAnswer(pc1, pc2);
- pc1.getTransceivers()[0].stop();
- await exchangeOfferAnswer(pc1, pc2);
- await pc1.setLocalDescription(await pc1.createOffer());
-}, 'If a transceiver is stopped locally, setting a locally generated answer should still work');
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
- await exchangeOfferAnswer(pc1, pc2);
- pc2.getTransceivers()[0].stop();
- await exchangeOfferAnswer(pc2, pc1);
- await pc1.setLocalDescription(await pc1.createOffer());
-}, 'If a transceiver is stopped remotely, setting a locally generated answer should still work');
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
- await exchangeOfferAnswer(pc1, pc2);
- assert_equals(pc1.getTransceivers().length, 1);
- assert_equals(pc2.getTransceivers().length, 1);
- pc1.getTransceivers()[0].stop();
- await exchangeOfferAnswer(pc1, pc2);
- assert_equals(pc1.getTransceivers().length, 0);
- assert_equals(pc2.getTransceivers().length, 0);
- assert_equals(pc1.getSenders().length, 0, 'caller senders');
- assert_equals(pc1.getReceivers().length, 0, 'caller receivers');
- assert_equals(pc2.getSenders().length, 0, 'callee senders');
- assert_equals(pc2.getReceivers().length, 0, 'callee receivers');
-}, 'If a transceiver is stopped, transceivers, senders and receivers should disappear after offer/answer');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-['audio', 'video'].forEach((kind) => {
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver(kind);
- const trackEnded = new Promise(
- r => { transceiver.receiver.track.onended = () => { r(); } });
- assert_equals(transceiver.receiver.track.readyState, 'live');
- transceiver.stop();
- // Stopping triggers ending the track, but this happens asynchronously.
- assert_equals(transceiver.receiver.track.readyState, 'live');
- await trackEnded;
- assert_equals(transceiver.receiver.track.readyState, 'ended');
- }, `[${kind}] Locally stopping a transceiver ends the track`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const pc1Transceiver = pc1.addTransceiver(kind);
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
- const [pc2Transceiver] = pc2.getTransceivers();
-
- pc1Transceiver.stop();
-
- await pc1.setLocalDescription();
- assert_equals(pc2Transceiver.receiver.track.readyState, 'live');
- // Applying the remote offer immediately ends the track, we don't need to
- // create or apply an answer.
- await pc2.setRemoteDescription(pc1.localDescription);
- assert_equals(pc2Transceiver.receiver.track.readyState, 'ended');
- }, `[${kind}] Remotely stopping a transceiver ends the track`);
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const transceiver = pc.addTransceiver(kind);
-
- // Rollback does not end the track, because the transceiver is not removed.
- await pc.setLocalDescription();
- await pc.setLocalDescription({type:'rollback'});
- assert_equals(transceiver.receiver.track.readyState, 'live');
- }, `[${kind}] Rollback when transceiver is not removed does not end track`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const pc1Transceiver = pc1.addTransceiver(kind);
-
- // Start negotiation, causing a transceiver to be created.
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- const [pc2Transceiver] = pc2.getTransceivers();
-
- // Rollback such that the transceiver is removed.
- await pc2.setLocalDescription({type:'rollback'});
- assert_equals(pc2.getTransceivers().length, 0);
- assert_equals(pc2Transceiver.receiver.track.readyState, 'ended');
- }, `[${kind}] Rollback when removing transceiver does end the track`);
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const constraints = {};
- constraints[kind] = true;
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
- const [track] = stream.getTracks();
-
- pc1.addTrack(track);
- pc2.addTrack(track);
- const transceiver = pc2.getTransceivers()[0];
-
- const ontrackEvent = new Promise(r => {
- pc2.ontrack = e => r(e.track);
- });
-
- // Simulate glare: both peer connections set local offers.
- await pc1.setLocalDescription();
- await pc2.setLocalDescription();
- // Set remote offer, which implicitly rolls back the local offer. Because
- // `transceiver` is an addTrack-transceiver, it should get repurposed.
- await pc2.setRemoteDescription(pc1.localDescription);
- assert_equals(transceiver.receiver.track.readyState, 'live');
- // Sanity check: the track should still be live when ontrack fires.
- assert_equals((await ontrackEvent).readyState, 'live');
- }, `[${kind}] Glare when transceiver is not removed does not end track`);
-});
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCRtpTransceiver</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- const checkThrows = async (func, exceptionName, description) => {
- try {
- await func();
- assert_true(false, description + " throws " + exceptionName);
- } catch (e) {
- assert_equals(e.name, exceptionName, description + " throws " + exceptionName);
- }
- };
-
- const stopTracks = (...streams) => {
- streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
- };
-
- const collectEvents = (target, name, check) => {
- const events = [];
- const handler = e => {
- check(e);
- events.push(e);
- };
-
- target.addEventListener(name, handler);
-
- const finishCollecting = () => {
- target.removeEventListener(name, handler);
- return events;
- };
-
- return {finish: finishCollecting};
- };
-
- const collectAddTrackEvents = stream => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(stream.getTracks().includes(e.track),
- "track in addtrack event is in the stream");
- };
- return collectEvents(stream, "addtrack", checkEvent);
- };
-
- const collectRemoveTrackEvents = stream => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(!stream.getTracks().includes(e.track),
- "track in removetrack event is not in the stream");
- };
- return collectEvents(stream, "removetrack", checkEvent);
- };
-
- const collectTrackEvents = pc => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(e.receiver instanceof RTCRtpReceiver, "Receiver is set on event");
- assert_true(e.transceiver instanceof RTCRtpTransceiver, "Transceiver is set on event");
- assert_true(Array.isArray(e.streams), "Streams is set on event");
- e.streams.forEach(stream => {
- assert_true(stream.getTracks().includes(e.track),
- "Each stream in event contains the track");
- });
- assert_equals(e.receiver, e.transceiver.receiver,
- "Receiver belongs to transceiver");
- assert_equals(e.track, e.receiver.track,
- "Track belongs to receiver");
- };
-
- return collectEvents(pc, "track", checkEvent);
- };
-
- const setRemoteDescriptionReturnTrackEvents = async (pc, desc) => {
- const trackEventCollector = collectTrackEvents(pc);
- await pc.setRemoteDescription(desc);
- return trackEventCollector.finish();
- };
-
- const offerAnswer = async (offerer, answerer) => {
- const offer = await offerer.createOffer();
- await answerer.setRemoteDescription(offer);
- await offerer.setLocalDescription(offer);
- const answer = await answerer.createAnswer();
- await offerer.setRemoteDescription(answer);
- await answerer.setLocalDescription(answer);
- };
-
- const trickle = (t, pc1, pc2) => {
- pc1.onicecandidate = t.step_func(async e => {
- try {
- await pc2.addIceCandidate(e.candidate);
- } catch (e) {
- assert_true(false, "addIceCandidate threw error: " + e.name);
- }
- });
- };
-
- const iceConnected = pc => {
- return new Promise((resolve, reject) => {
- const iceCheck = () => {
- if (pc.iceConnectionState == "connected") {
- assert_true(true, "ICE connected");
- resolve();
- }
-
- if (pc.iceConnectionState == "failed") {
- assert_true(false, "ICE failed");
- reject();
- }
- };
-
- iceCheck();
- pc.oniceconnectionstatechange = iceCheck;
- });
- };
-
- const negotiationNeeded = pc => {
- return new Promise(resolve => pc.onnegotiationneeded = resolve);
- };
-
- const countEvents = (target, name) => {
- const result = {count: 0};
- target.addEventListener(name, e => result.count++);
- return result;
- };
-
- const gotMuteEvent = async track => {
- await new Promise(r => track.addEventListener("mute", r, {once: true}));
-
- assert_true(track.muted, "track should be muted after onmute");
- };
-
- const gotUnmuteEvent = async track => {
- await new Promise(r => track.addEventListener("unmute", r, {once: true}));
-
- assert_true(!track.muted, "track should not be muted after onunmute");
- };
-
- // comparable() - produces copy of object that is JSON comparable.
- // o = original object (required)
- // t = template of what to examine. Useful if o is non-enumerable (optional)
-
- const comparable = (o, t = o) => {
- if (typeof o != 'object' || !o) {
- return o;
- }
- if (Array.isArray(t) && Array.isArray(o)) {
- return o.map((n, i) => comparable(n, t[i]));
- }
- return Object.keys(t).sort()
- .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
- };
-
- const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
-
- const hasProps = (observed, expected) => {
- const observable = comparable(observed, expected);
- assert_equals(stripKeyQuotes(JSON.stringify(observable)),
- stripKeyQuotes(JSON.stringify(comparable(expected))));
- };
-
- const hasPropsAndUniqueMids = (observed, expected) => {
- hasProps(observed, expected);
-
- const mids = [];
- observed.forEach((transceiver, i) => {
- if (!("mid" in expected[i])) {
- assert_not_equals(transceiver.mid, null);
- assert_equals(typeof transceiver.mid, "string");
- }
- if (transceiver.mid) {
- assert_false(mids.includes(transceiver.mid), "mid must be unique");
- mids.push(transceiver.mid);
- }
- });
- };
-
- const checkAddTransceiverNoTrack = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- hasProps(pc.getTransceivers(), []);
-
- pc.addTransceiver("audio");
- pc.addTransceiver("video");
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio", readyState: "live", muted: true}},
- sender: {track: null},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- },
- {
- receiver: {track: {kind: "video", readyState: "live", muted: true}},
- sender: {track: null},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverWithTrack = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
-
- pc.addTransceiver(audio);
- pc.addTransceiver(video);
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: audio},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- },
- {
- receiver: {track: {kind: "video"}},
- sender: {track: video},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverWithAddTrack = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
-
- pc.addTrack(audio, stream);
- pc.addTrack(video, stream);
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: audio},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- },
- {
- receiver: {track: {kind: "video"}},
- sender: {track: video},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverWithDirection = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver("audio", {direction: "recvonly"});
- pc.addTransceiver("video", {direction: "recvonly"});
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- mid: null,
- currentDirection: null,
- },
- {
- receiver: {track: {kind: "video"}},
- sender: {track: null},
- direction: "recvonly",
- mid: null,
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverWithSetRemoteOfferSending = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTransceiver(track, {streams: [stream]});
-
- const offer = await pc1.createOffer();
-
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverWithSetRemoteOfferNoSend = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTransceiver(track);
- pc1.getTransceivers()[0].direction = "recvonly";
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents, []);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- // rtcweb-jsep says this is recvonly, w3c-webrtc does not...
- direction: "recvonly",
- currentDirection: null,
- }
- ]);
- };
-
- const checkAddTransceiverBadKind = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- try {
- pc.addTransceiver("foo");
- assert_true(false, 'addTransceiver("foo") throws');
- }
- catch (e) {
- if (e instanceof TypeError) {
- assert_true(true, 'addTransceiver("foo") throws a TypeError');
- } else {
- assert_true(false, 'addTransceiver("foo") throws a TypeError');
- }
- }
-
- hasProps(pc.getTransceivers(), []);
- };
-
- const checkMsidNoTrackId = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- // Remove track-id from msid
- // Fixate stream-id so that error message is consistent.
- offer.sdp = offer.sdp.replace(/(a=msid:[^ \t]+).*\r\n/g,
- "a=msid:fake-stream-id\r\n");
- await pc2.setRemoteDescription(offer);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- };
-
- const checkNoMidOffer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
-
- // Remove mid attr
- offer.sdp = offer.sdp.replace("a=mid:", "a=unknownattr:");
- offer.sdp = offer.sdp.replace("a=group:", "a=unknownattr:");
- await pc2.setRemoteDescription(offer);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- currentDirection: null,
- }
- ]);
-
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- };
-
- const checkNoMidAnswer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
-
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: {kind: "audio"}},
- direction: "sendrecv",
- currentDirection: null,
- }
- ]);
-
- const lastMid = pc1.getTransceivers()[0].mid;
-
- let answer = await pc2.createAnswer();
- // Remove mid attr
- answer.sdp = answer.sdp.replace("a=mid:", "a=unknownattr:");
- // Remove group attr also
- answer.sdp = answer.sdp.replace("a=group:", "a=unknownattr:");
- await pc1.setRemoteDescription(answer);
-
- hasProps(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: {kind: "audio"}},
- direction: "sendrecv",
- currentDirection: "sendonly",
- mid: lastMid
- }
- ]);
-
- const reoffer = await pc1.createOffer();
- await pc1.setLocalDescription(reoffer);
- hasProps(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: {kind: "audio"}},
- direction: "sendrecv",
- currentDirection: "sendonly",
- mid: lastMid
- }
- ]);
- };
-
- const checkAddTransceiverNoTrackDoesntPair = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- pc1.addTransceiver("audio");
- pc2.addTransceiver("audio");
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[1].receiver.track,
- streams: []
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {mid: null}, // no addTrack magic, doesn't auto-pair
- {} // Created by SRD
- ]);
- };
-
- const checkAddTransceiverWithTrackDoesntPair = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc2.addTransceiver(track);
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[1].receiver.track,
- streams: []
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {mid: null, sender: {track}},
- {sender: {track: null}} // Created by SRD
- ]);
- };
-
- const checkAddTransceiverThenReplaceTrackDoesntPair = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
- pc2.addTransceiver("audio");
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- await pc2.getTransceivers()[0].sender.replaceTrack(track);
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[1].receiver.track,
- streams: []
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {mid: null, sender: {track}},
- {sender: {track: null}} // Created by SRD
- ]);
- };
-
- const checkAddTransceiverThenAddTrackPairs = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
- pc2.addTransceiver("audio");
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc2.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: []
- }
- ]);
-
- // addTransceiver-transceivers cannot attach to a remote offers, so a second
- // transceiver is created and associated whilst the first transceiver
- // remains unassociated.
- assert_equals(pc2.getTransceivers()[0].mid, null);
- assert_not_equals(pc2.getTransceivers()[1].mid, null);
- };
-
- const checkAddTrackPairs = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc2.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: []
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {sender: {track}}
- ]);
- };
-
- const checkReplaceTrackNullDoesntPreventPairing = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.addTransceiver("audio");
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc2.addTrack(track, stream);
- await pc2.getTransceivers()[0].sender.replaceTrack(null);
-
- const offer = await pc1.createOffer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: []
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {sender: {track: null}}
- ]);
- };
-
- const checkRemoveAndReadd = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
-
- await offerAnswer(pc1, pc2);
-
- pc1.removeTrack(pc1.getSenders()[0]);
- pc1.addTrack(track, stream);
-
- hasProps(pc1.getTransceivers(),
- [
- {
- sender: {track: null},
- direction: "recvonly"
- },
- {
- sender: {track},
- direction: "sendrecv"
- }
- ]);
-
- // pc1 is offerer
- await offerAnswer(pc1, pc2);
-
- hasProps(pc2.getTransceivers(),
- [
- {currentDirection: "inactive"},
- {currentDirection: "recvonly"}
- ]);
-
- pc1.removeTrack(pc1.getSenders()[1]);
- pc1.addTrack(track, stream);
-
- hasProps(pc1.getTransceivers(),
- [
- {
- sender: {track: null},
- direction: "recvonly"
- },
- {
- sender: {track: null},
- direction: "recvonly"
- },
- {
- sender: {track},
- direction: "sendrecv"
- }
- ]);
-
- // pc1 is answerer. We need to create a new transceiver so pc1 will have
- // something to attach the re-added track to
- pc2.addTransceiver("audio");
-
- await offerAnswer(pc2, pc1);
-
- hasProps(pc2.getTransceivers(),
- [
- {currentDirection: "inactive"},
- {currentDirection: "inactive"},
- {currentDirection: "sendrecv"}
- ]);
- };
-
- const checkAddTrackExistingTransceiverThenRemove = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver("audio");
- const stream = await getNoiseStream({audio: true});
- const audio = stream.getAudioTracks()[0];
- let sender = pc.addTrack(audio, stream);
- pc.removeTrack(sender);
-
- // Cause transceiver to be associated
- await pc.setLocalDescription(await pc.createOffer());
-
- // Make sure add/remove works still
- sender = pc.addTrack(audio, stream);
- pc.removeTrack(sender);
-
- stopTracks(stream);
- };
-
- const checkRemoveTrackNegotiation = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- pc1.addTrack(audio, stream);
- const video = stream.getVideoTracks()[0];
- pc1.addTrack(video, stream);
- // We want both a sendrecv and sendonly transceiver to test that the
- // appropriate direction changes happen.
- pc1.getTransceivers()[1].direction = "sendonly";
-
- let offer = await pc1.createOffer();
-
- // Get a reference to the stream
- let trackEventCollector = collectTrackEvents(pc2);
- await pc2.setRemoteDescription(offer);
- let pc2TrackEvents = trackEventCollector.finish();
- hasProps(pc2TrackEvents,
- [
- {streams: [{id: stream.id}]},
- {streams: [{id: stream.id}]}
- ]);
- const receiveStream = pc2TrackEvents[0].streams[0];
-
- // Verify that rollback causes onremovetrack to fire for the added tracks
- let removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
- await pc2.setRemoteDescription({type: "rollback"});
- let removedtracks = removetrackEventCollector.finish().map(e => e.track);
- assert_equals(removedtracks.length, 2,
- "Rollback should have removed two tracks");
- assert_true(removedtracks.includes(pc2TrackEvents[0].track),
- "First track should be removed");
- assert_true(removedtracks.includes(pc2TrackEvents[1].track),
- "Second track should be removed");
-
- offer = await pc1.createOffer();
-
- let addtrackEventCollector = collectAddTrackEvents(receiveStream);
- trackEventCollector = collectTrackEvents(pc2);
- await pc2.setRemoteDescription(offer);
- pc2TrackEvents = trackEventCollector.finish();
- let addedtracks = addtrackEventCollector.finish().map(e => e.track);
- assert_equals(addedtracks.length, 2,
- "pc2.setRemoteDescription(offer) should've added 2 tracks to receive stream");
- assert_true(addedtracks.includes(pc2TrackEvents[0].track),
- "First track should be added");
- assert_true(addedtracks.includes(pc2TrackEvents[1].track),
- "Second track should be added");
-
- await pc1.setLocalDescription(offer);
- let answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- pc1.removeTrack(pc1.getSenders()[0]);
-
- hasProps(pc1.getSenders(),
- [
- {track: null},
- {track: video}
- ]);
-
- hasProps(pc1.getTransceivers(),
- [
- {
- sender: {track: null},
- direction: "recvonly"
- },
- {
- sender: {track: video},
- direction: "sendonly"
- }
- ]);
-
- await negotiationNeeded(pc1);
-
- pc1.removeTrack(pc1.getSenders()[1]);
-
- hasProps(pc1.getSenders(),
- [
- {track: null},
- {track: null}
- ]);
-
- hasProps(pc1.getTransceivers(),
- [
- {
- sender: {track: null},
- direction: "recvonly"
- },
- {
- sender: {track: null},
- direction: "inactive"
- }
- ]);
-
- // pc1 as offerer
- offer = await pc1.createOffer();
-
- removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
- await pc2.setRemoteDescription(offer);
- removedtracks = removetrackEventCollector.finish().map(e => e.track);
- assert_equals(removedtracks.length, 2, "Should have two removed tracks");
- assert_true(removedtracks.includes(pc2TrackEvents[0].track),
- "First track should be removed");
- assert_true(removedtracks.includes(pc2TrackEvents[1].track),
- "Second track should be removed");
-
- addtrackEventCollector = collectAddTrackEvents(receiveStream);
- await pc2.setRemoteDescription({type: "rollback"});
- addedtracks = addtrackEventCollector.finish().map(e => e.track);
- assert_equals(addedtracks.length, 2, "Rollback should have added two tracks");
-
- // pc2 as offerer
- offer = await pc2.createOffer();
- await pc2.setLocalDescription(offer);
- await pc1.setRemoteDescription(offer);
- answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
-
- removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
- await pc2.setRemoteDescription(answer);
- removedtracks = removetrackEventCollector.finish().map(e => e.track);
- assert_equals(removedtracks.length, 2, "Should have two removed tracks");
-
- hasProps(pc2.getTransceivers(),
- [
- {
- currentDirection: "inactive"
- },
- {
- currentDirection: "inactive"
- }
- ]);
- };
-
- const checkSetDirection = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- pc.addTransceiver("audio");
-
- pc.getTransceivers()[0].direction = "sendonly";
- hasProps(pc.getTransceivers(),[{direction: "sendonly"}]);
- pc.getTransceivers()[0].direction = "recvonly";
- hasProps(pc.getTransceivers(),[{direction: "recvonly"}]);
- pc.getTransceivers()[0].direction = "inactive";
- hasProps(pc.getTransceivers(),[{direction: "inactive"}]);
- pc.getTransceivers()[0].direction = "sendrecv";
- hasProps(pc.getTransceivers(),[{direction: "sendrecv"}]);
- };
-
- const checkCurrentDirection = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
- hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
-
- let offer = await pc1.createOffer();
- hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
-
- await pc1.setLocalDescription(offer);
- hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
-
- let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- hasProps(pc2.getTransceivers(), [{currentDirection: null}]);
-
- let answer = await pc2.createAnswer();
- hasProps(pc2.getTransceivers(), [{currentDirection: null}]);
-
- await pc2.setLocalDescription(answer);
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- pc2.getTransceivers()[0].direction = "sendonly";
-
- offer = await pc2.createOffer();
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- await pc2.setLocalDescription(offer);
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
- hasProps(trackEvents, []);
-
- hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- answer = await pc1.createAnswer();
- hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- await pc1.setLocalDescription(answer);
- hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
- hasProps(trackEvents, []);
-
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
-
- pc2.getTransceivers()[0].direction = "sendrecv";
-
- offer = await pc2.createOffer();
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
-
- await pc2.setLocalDescription(offer);
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
- hasProps(trackEvents, []);
-
- hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
-
- answer = await pc1.createAnswer();
- hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
-
- await pc1.setLocalDescription(answer);
- hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
-
- pc2.close();
- hasProps(pc2.getTransceivers(), [{currentDirection: "stopped"}]);
- };
-
- const checkSendrecvWithNoSendTrack = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTransceiver("audio");
- pc1.getTransceivers()[0].direction = "sendrecv";
- pc2.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
-
- let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: []
- }
- ]);
-
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
-
- const answer = await pc2.createAnswer();
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- // Spec language doesn't say anything about checking whether the transceiver
- // is stopped here.
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- trickle(t, pc2, pc1);
- await pc2.setLocalDescription(answer);
-
- await iceConnected(pc1);
- await iceConnected(pc2);
- };
-
- const checkSendrecvWithTracklessStream = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = new MediaStream();
- pc1.addTransceiver("audio", {streams: [stream]});
-
- const offer = await pc1.createOffer();
-
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
- };
-
- const checkMute = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const stream1 = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream1));
- const audio1 = stream1.getAudioTracks()[0];
- pc1.addTrack(audio1, stream1);
- const countMuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "mute");
- const countUnmuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "unmute");
-
- const video1 = stream1.getVideoTracks()[0];
- pc1.addTrack(video1, stream1);
- const countMuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "mute");
- const countUnmuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "unmute");
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const stream2 = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream2));
- const audio2 = stream2.getAudioTracks()[0];
- pc2.addTrack(audio2, stream2);
- const countMuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "mute");
- const countUnmuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "unmute");
-
- const video2 = stream2.getVideoTracks()[0];
- pc2.addTrack(video2, stream2);
- const countMuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "mute");
- const countUnmuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "unmute");
-
-
- // Check that receive tracks start muted
- hasProps(pc1.getTransceivers(),
- [
- {receiver: {track: {kind: "audio", muted: true}}},
- {receiver: {track: {kind: "video", muted: true}}}
- ]);
-
- hasProps(pc1.getTransceivers(),
- [
- {receiver: {track: {kind: "audio", muted: true}}},
- {receiver: {track: {kind: "video", muted: true}}}
- ]);
-
- let offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
- let answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- trickle(t, pc2, pc1);
- await pc2.setLocalDescription(answer);
-
- let gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
- let gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
-
- let gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
- let gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
- // Jump out before waiting if a track is unmuted before RTP starts flowing.
- assert_true(pc1.getTransceivers()[0].receiver.track.muted);
- assert_true(pc1.getTransceivers()[1].receiver.track.muted);
- assert_true(pc2.getTransceivers()[0].receiver.track.muted);
- assert_true(pc2.getTransceivers()[1].receiver.track.muted);
-
- await iceConnected(pc1);
- await iceConnected(pc2);
-
-
- // Check that receive tracks are unmuted when RTP starts flowing
- await gotUnmuteAudio1;
- await gotUnmuteVideo1;
- await gotUnmuteAudio2;
- await gotUnmuteVideo2;
-
- // Check whether disabling recv locally causes onmute
- pc1.getTransceivers()[0].direction = "sendonly";
- pc1.getTransceivers()[1].direction = "sendonly";
- offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc1.setLocalDescription(offer);
- answer = await pc2.createAnswer();
- const gotMuteAudio1 = gotMuteEvent(pc1.getTransceivers()[0].receiver.track);
- const gotMuteVideo1 = gotMuteEvent(pc1.getTransceivers()[1].receiver.track);
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- await gotMuteAudio1;
- await gotMuteVideo1;
-
- // Check whether disabling on remote causes onmute
- pc1.getTransceivers()[0].direction = "inactive";
- pc1.getTransceivers()[1].direction = "inactive";
- offer = await pc1.createOffer();
- const gotMuteAudio2 = gotMuteEvent(pc2.getTransceivers()[0].receiver.track);
- const gotMuteVideo2 = gotMuteEvent(pc2.getTransceivers()[1].receiver.track);
- await pc2.setRemoteDescription(offer);
- await gotMuteAudio2;
- await gotMuteVideo2;
- await pc1.setLocalDescription(offer);
- answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
-
- // Check whether onunmute fires when we turn everything on again
- pc1.getTransceivers()[0].direction = "sendrecv";
- pc1.getTransceivers()[1].direction = "sendrecv";
- offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc1.setLocalDescription(offer);
- answer = await pc2.createAnswer();
- gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
- gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
- gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
- gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
- await pc1.setRemoteDescription(answer);
- await pc2.setLocalDescription(answer);
- await gotUnmuteAudio1;
- await gotUnmuteVideo1;
- await gotUnmuteAudio2;
- await gotUnmuteVideo2;
-
- // Wait a little, just in case some stray events fire
- await new Promise(r => t.step_timeout(r, 100));
-
- assert_equals(1, countMuteAudio1.count, "Got 1 mute event for pc1's audio track");
- assert_equals(1, countMuteVideo1.count, "Got 1 mute event for pc1's video track");
- assert_equals(1, countMuteAudio2.count, "Got 1 mute event for pc2's audio track");
- assert_equals(1, countMuteVideo2.count, "Got 1 mute event for pc2's video track");
- assert_equals(2, countUnmuteAudio1.count, "Got 2 unmute events for pc1's audio track");
- assert_equals(2, countUnmuteVideo1.count, "Got 2 unmute events for pc1's video track");
- assert_equals(2, countUnmuteAudio2.count, "Got 2 unmute events for pc2's audio track");
- assert_equals(2, countUnmuteVideo2.count, "Got 2 unmute events for pc2's video track");
- };
-
- const checkStop = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- await pc2.setRemoteDescription(offer);
-
- pc2.addTrack(track, stream);
-
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- let stoppedTransceiver = pc1.getTransceivers()[0];
- let onended = new Promise(resolve => {
- stoppedTransceiver.receiver.track.onended = resolve;
- });
- stoppedTransceiver.stop();
- assert_equals(pc1.getReceivers().length, 1, 'getReceivers exposes a receiver of a stopped transceiver before negotiation');
- assert_equals(pc1.getSenders().length, 1, 'getSenders exposes a sender of a stopped transceiver before negotiation');
- await onended;
- // The transceiver has [[stopping]] = true, [[stopped]] = false
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- sender: {track: {kind: "audio"}},
- receiver: {track: {kind: "audio", readyState: "ended"}},
- currentDirection: "sendrecv",
- direction: "stopped"
- }
- ]);
-
- const transceiver = pc1.getTransceivers()[0];
-
- checkThrows(() => transceiver.sender.setParameters(
- transceiver.sender.getParameters()),
- "InvalidStateError", "setParameters on stopped transceiver");
-
- const stream2 = await getNoiseStream({audio: true});
- const track2 = stream.getAudioTracks()[0];
- checkThrows(() => transceiver.sender.replaceTrack(track2),
- "InvalidStateError", "replaceTrack on stopped transceiver");
-
- checkThrows(() => transceiver.direction = "sendrecv",
- "InvalidStateError", "set direction on stopped transceiver");
-
- checkThrows(() => transceiver.sender.dtmf.insertDTMF("111"),
- "InvalidStateError", "insertDTMF on stopped transceiver");
-
- // Shouldn't throw
- stoppedTransceiver.stop();
-
- offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
-
- const stoppedCalleeTransceiver = pc2.getTransceivers()[0];
- onended = new Promise(resolve => {
- stoppedCalleeTransceiver.receiver.track.onended = resolve;
- });
-
- await pc2.setRemoteDescription(offer);
-
- await onended;
- // pc2's transceiver was stopped remotely.
- // The track ends when setRemeoteDescription(offer) is set.
- hasProps(pc2.getTransceivers(),
- [
- {
- sender: {track: {kind: "audio"}},
- receiver: {track: {kind: "audio", readyState: "ended"}},
- currentDirection: "stopped",
- direction: "stopped"
- }
- ]);
- // After setLocalDescription(answer), the transceiver has
- // [[stopping]] = true, [[stopped]] = true, and is removed from pc2.
- const stoppingAnswer = await pc2.createAnswer();
- await pc2.setLocalDescription(stoppingAnswer);
- assert_equals(pc2.getTransceivers().length, 0);
- assert_equals(pc2.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation');
- assert_equals(pc2.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation');
-
- // Shouldn't throw either
- stoppedTransceiver.stop();
- await pc1.setRemoteDescription(stoppingAnswer);
- assert_equals(pc1.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation');
- assert_equals(pc1.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation');
-
- pc1.close();
- pc2.close();
-
- // Spec says the closed check comes before the stopped check, so this
- // should throw now.
- checkThrows(() => stoppedTransceiver.stop(),
- "InvalidStateError", "RTCRtpTransceiver.stop() with closed PC");
- };
-
- const checkStopAfterCreateOffer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
-
- const transceiverThatWasStopped = pc1.getTransceivers()[0];
- transceiverThatWasStopped.stop();
- await pc2.setRemoteDescription(offer)
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
-
- let answer = await pc2.createAnswer();
- const negotiationNeededAwaiter = negotiationNeeded(pc1);
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- // Spec language doesn't say anything about checking whether the transceiver
- // is stopped here.
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- assert_equals(transceiverThatWasStopped, pc1.getTransceivers()[0]);
- // The transceiver should still be [[stopping]]=true, [[stopped]]=false.
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- currentDirection: "sendrecv",
- direction: "stopped"
- }
- ]);
-
- await negotiationNeededAwaiter;
-
- trickle(t, pc2, pc1);
-
- await pc2.setLocalDescription(answer);
-
- await iceConnected(pc1);
- await iceConnected(pc2);
-
- offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- assert_equals(pc1.getTransceivers().length, 0);
- assert_equals(pc2.getTransceivers().length, 0);
- };
-
- const checkStopAfterSetLocalOffer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
-
- await pc2.setRemoteDescription(offer)
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
-
- pc1.getTransceivers()[0].stop();
-
- let answer = await pc2.createAnswer();
- const negotiationNeededAwaiter = negotiationNeeded(pc1);
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- // Spec language doesn't say anything about checking whether the transceiver
- // is stopped here.
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: "sendrecv"
- }
- ]);
- await negotiationNeededAwaiter;
-
- trickle(t, pc2, pc1);
- await pc2.setLocalDescription(answer);
-
- await iceConnected(pc1);
- await iceConnected(pc2);
-
- offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- assert_equals(pc1.getTransceivers().length, 0);
- assert_equals(pc2.getTransceivers().length, 0);
- };
-
- const checkStopAfterSetRemoteOffer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
-
- await pc2.setRemoteDescription(offer)
- await pc1.setLocalDescription(offer);
-
- // Stop on _answerer_ side now. Should not stop transceiver in answer,
- // but cause firing of negotiationNeeded at pc2, and disabling
- // of the transceiver with direction = inactive in answer.
- pc2.getTransceivers()[0].stop();
- assert_equals(pc2.getTransceivers()[0].direction, 'stopped');
-
- const answer = await pc2.createAnswer();
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- hasProps(trackEvents, []);
-
- hasProps(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: null,
- }
- ]);
-
- const negotiationNeededAwaiter = negotiationNeeded(pc2);
- await pc2.setLocalDescription(answer);
- hasProps(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: "inactive",
- }
- ]);
-
- await negotiationNeededAwaiter;
- };
-
- const checkStopAfterCreateAnswer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
-
- await pc2.setRemoteDescription(offer)
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
-
- let answer = await pc2.createAnswer();
-
- // Too late for this to go in the answer. ICE should succeed.
- pc2.getTransceivers()[0].stop();
-
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: null,
- }
- ]);
-
- trickle(t, pc2, pc1);
- // The negotiationneeded event is fired during processing of
- // setLocalDescription()
- const negotiationNeededAwaiter = negotiationNeeded(pc2);
- await pc2.setLocalDescription(answer);
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: "sendrecv",
- }
- ]);
-
- await negotiationNeededAwaiter;
- await iceConnected(pc1);
- await iceConnected(pc2);
-
- offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
- answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- // Since this offer/answer exchange was initiated from pc1,
- // pc2 still doesn't get to say that it has a stopped transceiver,
- // but does get to set it to inactive.
- hasProps(pc1.getTransceivers(),
- [
- {
- direction: "sendrecv",
- currentDirection: "inactive",
- }
- ]);
-
- hasProps(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: "inactive",
- }
- ]);
- };
-
- const checkStopAfterSetLocalAnswer = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
-
- await pc2.setRemoteDescription(offer)
- trickle(t, pc1, pc2);
- await pc1.setLocalDescription(offer);
-
- let answer = await pc2.createAnswer();
-
- const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- trickle(t, pc2, pc1);
- await pc2.setLocalDescription(answer);
-
- // ICE should succeed.
- pc2.getTransceivers()[0].stop();
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- direction: "stopped",
- currentDirection: "sendrecv",
- }
- ]);
-
- await negotiationNeeded(pc2);
- await iceConnected(pc1);
- await iceConnected(pc2);
-
- // Initiate an offer/answer exchange from pc2 in order
- // to negotiate the stopped transceiver.
- offer = await pc2.createOffer();
- await pc2.setLocalDescription(offer);
- await pc1.setRemoteDescription(offer);
- answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
- await pc2.setRemoteDescription(answer);
-
- assert_equals(pc1.getTransceivers().length, 0);
- assert_equals(pc2.getTransceivers().length, 0);
- };
-
- const checkStopAfterClose = async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
-
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer)
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- pc1.close();
- await checkThrows(() => pc1.getTransceivers()[0].stop(),
- "InvalidStateError",
- "Stopping a transceiver on a closed PC should throw.");
- };
-
- const checkLocalRollback = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc.addTrack(track, stream);
-
- let offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
-
- hasPropsAndUniqueMids(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track},
- direction: "sendrecv",
- currentDirection: null,
- }
- ]);
-
- // Verify that rollback doesn't stomp things it should not
- pc.getTransceivers()[0].direction = "sendonly";
- const stream2 = await getNoiseStream({audio: true});
- const track2 = stream2.getAudioTracks()[0];
- await pc.getTransceivers()[0].sender.replaceTrack(track2);
-
- await pc.setLocalDescription({type: "rollback"});
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: track2},
- direction: "sendonly",
- mid: null,
- currentDirection: null,
- }
- ]);
-
- // Make sure stop() isn't rolled back either.
- offer = await pc.createOffer();
- await pc.setLocalDescription(offer);
- pc.getTransceivers()[0].stop();
- await pc.setLocalDescription({type: "rollback"});
-
- hasProps(pc.getTransceivers(), [
- {
- direction: "stopped",
- }
- ]);
- };
-
- const checkRollbackAndSetRemoteOfferWithDifferentType = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- const audioStream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(audioStream));
- const audioTrack = audioStream.getAudioTracks()[0];
- pc1.addTrack(audioTrack, audioStream);
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const videoStream = await getNoiseStream({video: true});
- t.add_cleanup(() => stopTracks(videoStream));
- const videoTrack = videoStream.getVideoTracks()[0];
- pc2.addTrack(videoTrack, videoStream);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- await pc1.setLocalDescription({type: "rollback"});
-
- hasProps(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: audioTrack},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
-
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "video"}},
- sender: {track: videoTrack},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
-
- await offerAnswer(pc2, pc1);
-
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: audioTrack},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- },
- {
- receiver: {track: {kind: "video"}},
- sender: {track: null},
- direction: "recvonly",
- currentDirection: "recvonly",
- }
- ]);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "video"}},
- sender: {track: videoTrack},
- direction: "sendrecv",
- currentDirection: "sendonly",
- }
- ]);
-
- await offerAnswer(pc1, pc2);
- };
-
- const checkRemoteRollback = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
-
- let offer = await pc1.createOffer();
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- await pc2.setRemoteDescription(offer);
-
- const removedTransceiver = pc2.getTransceivers()[0];
-
- const onended = new Promise(resolve => {
- removedTransceiver.receiver.track.onended = resolve;
- });
-
- await pc2.setRemoteDescription({type: "rollback"});
-
- // Transceiver should be _gone_
- hasProps(pc2.getTransceivers(), []);
-
- hasProps(removedTransceiver,
- {
- mid: null,
- currentDirection: "stopped"
- }
- );
-
- await onended;
-
- hasProps(removedTransceiver,
- {
- receiver: {track: {readyState: "ended"}},
- mid: null,
- currentDirection: "stopped"
- }
- );
-
- // Setting the same offer again should do the same thing as before
- await pc2.setRemoteDescription(offer);
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- currentDirection: null,
- }
- ]);
-
- const mid0 = pc2.getTransceivers()[0].mid;
-
- // Give pc2 a track with replaceTrack
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream2));
- const track2 = stream2.getAudioTracks()[0];
- await pc2.getTransceivers()[0].sender.replaceTrack(track2);
- pc2.getTransceivers()[0].direction = "sendrecv";
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: track2},
- direction: "sendrecv",
- mid: mid0,
- currentDirection: null,
- }
- ]);
-
- await pc2.setRemoteDescription({type: "rollback"});
-
- // Transceiver should be _gone_, again. replaceTrack doesn't prevent this,
- // nor does setting direction.
- hasProps(pc2.getTransceivers(), []);
-
- // Setting the same offer for a _third_ time should do the same thing
- await pc2.setRemoteDescription(offer);
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- mid: mid0,
- currentDirection: null,
- }
- ]);
-
- // We should be able to add the same track again
- pc2.addTrack(track2, stream2);
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: track2},
- direction: "sendrecv",
- mid: mid0,
- currentDirection: null,
- }
- ]);
-
- await pc2.setRemoteDescription({type: "rollback"});
- // Transceiver should _not_ be gone this time, because addTrack touched it.
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: track2},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- }
- ]);
-
- // Complete negotiation so we can test interactions with transceiver.stop()
- await pc1.setLocalDescription(offer);
-
- // After all this SRD/rollback, we should still get the track event
- let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
-
- assert_equals(trackEvents.length, 1);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
-
- // Make sure all this rollback hasn't messed up the signaling
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- assert_equals(trackEvents.length, 1);
- hasProps(trackEvents,
- [
- {
- track: pc1.getTransceivers()[0].receiver.track,
- streams: [{id: stream2.id}]
- }
- ]);
- hasProps(pc1.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track},
- direction: "sendrecv",
- mid: mid0,
- currentDirection: "sendrecv",
- }
- ]);
-
- // Don't bother waiting for ICE and such
-
- // Check to see whether rolling back a remote track removal works
- pc1.getTransceivers()[0].direction = "recvonly";
- offer = await pc1.createOffer();
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents, []);
-
- trackEvents =
- await setRemoteDescriptionReturnTrackEvents(pc2, {type: "rollback"});
-
- assert_equals(trackEvents.length, 1, 'track event from remote rollback');
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[0].receiver.track,
- streams: [{id: stream.id}]
- }
- ]);
-
- // Check to see that stop() cannot be rolled back
- pc1.getTransceivers()[0].stop();
- offer = await pc1.createOffer();
-
- await pc2.setRemoteDescription(offer);
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: track2},
- direction: "stopped",
- mid: mid0,
- currentDirection: "stopped",
- }
- ]);
-
- // stop() cannot be rolled back!
- // Transceiver should have [[stopping]]=true, [[stopped]]=false.
- await pc2.setRemoteDescription({type: "rollback"});
- hasProps(pc2.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: {kind: "audio"}},
- direction: "stopped",
- mid: mid0,
- currentDirection: "stopped",
- }
- ]);
- };
-
- const checkBundleTagRejected = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream1 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream1));
- const track1 = stream1.getAudioTracks()[0];
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream2));
- const track2 = stream2.getAudioTracks()[0];
-
- pc1.addTrack(track1, stream1);
- pc1.addTrack(track2, stream2);
-
- await offerAnswer(pc1, pc2);
-
- pc2.getTransceivers()[0].stop();
-
- await offerAnswer(pc1, pc2);
- await offerAnswer(pc2, pc1);
- };
-
- const checkMsectionReuse = async t => {
- // Use max-compat to make it easier to check for disabled m-sections
- const pc1 = new RTCPeerConnection({ bundlePolicy: "max-compat" });
- const pc2 = new RTCPeerConnection({ bundlePolicy: "max-compat" });
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream));
- const track = stream.getAudioTracks()[0];
- pc1.addTrack(track, stream);
- const [pc1Transceiver] = pc1.getTransceivers();
-
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
-
- // Answerer stops transceiver. The m-section is not immediately rejected
- // (a follow-up O/A exchange is needed) but it should become inactive in
- // the meantime.
- const stoppedMid0 = pc2.getTransceivers()[0].mid;
- const [pc2Transceiver] = pc2.getTransceivers();
- pc2Transceiver.stop();
- assert_equals(pc2.getTransceivers()[0].direction, "stopped");
- assert_not_equals(pc2.getTransceivers()[0].currentDirection, "stopped");
-
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-
- // Still not stopped - but inactive is reflected!
- assert_equals(pc1Transceiver.mid, stoppedMid0);
- assert_equals(pc1Transceiver.direction, "sendrecv");
- assert_equals(pc1Transceiver.currentDirection, "inactive");
- assert_equals(pc2Transceiver.mid, stoppedMid0);
- assert_equals(pc2Transceiver.direction, "stopped");
- assert_equals(pc2Transceiver.currentDirection, "inactive");
-
- // Now do the follow-up O/A exchange pc2 -> pc1.
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
-
- // Now they're stopped, and have been removed from the PCs.
- assert_equals(pc1.getTransceivers().length, 0);
- assert_equals(pc2.getTransceivers().length, 0);
- assert_equals(pc1Transceiver.mid, null);
- assert_equals(pc1Transceiver.direction, "stopped");
- assert_equals(pc1Transceiver.currentDirection, "stopped");
- assert_equals(pc2Transceiver.mid, null);
- assert_equals(pc2Transceiver.direction, "stopped");
- assert_equals(pc2Transceiver.currentDirection, "stopped");
-
- // Check that m-section is reused on both ends
- const stream2 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream2));
- const track2 = stream2.getAudioTracks()[0];
-
- pc1.addTrack(track2, stream2);
- let offer = await pc1.createOffer();
- assert_equals(offer.sdp.match(/m=/g).length, 1,
- "Exactly one m-line in offer, because it was reused");
- hasProps(pc1.getTransceivers(),
- [
- {
- sender: {track: track2}
- }
- ]);
-
- assert_not_equals(pc1.getTransceivers()[0].mid, stoppedMid0);
-
- pc2.addTrack(track, stream);
- offer = await pc2.createOffer();
- assert_equals(offer.sdp.match(/m=/g).length, 1,
- "Exactly one m-line in offer, because it was reused");
- hasProps(pc2.getTransceivers(),
- [
- {
- sender: {track}
- }
- ]);
-
- assert_not_equals(pc2.getTransceivers()[0].mid, stoppedMid0);
-
- await pc2.setLocalDescription(offer);
- await pc1.setRemoteDescription(offer);
- let answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
- await pc2.setRemoteDescription(answer);
- hasPropsAndUniqueMids(pc1.getTransceivers(),
- [
- {
- sender: {track: track2},
- currentDirection: "sendrecv"
- }
- ]);
-
- const mid0 = pc1.getTransceivers()[0].mid;
-
- hasProps(pc2.getTransceivers(),
- [
- {
- sender: {track},
- currentDirection: "sendrecv",
- mid: mid0
- }
- ]);
-
- // stop the transceiver, and add a track. Verify that we don't reuse
- // prematurely in our offer. (There should be one rejected m-section, and a
- // new one for the new track)
- const stoppedMid1 = pc1.getTransceivers()[0].mid;
- pc1.getTransceivers()[0].stop();
- const stream3 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream3));
- const track3 = stream3.getAudioTracks()[0];
- pc1.addTrack(track3, stream3);
- offer = await pc1.createOffer();
- assert_equals(offer.sdp.match(/m=/g).length, 2,
- "Exactly 2 m-lines in offer, because it is too early to reuse");
- assert_equals(offer.sdp.match(/m=audio 0 /g).length, 1,
- "One m-line is rejected");
-
- await pc1.setLocalDescription(offer);
-
- let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
- hasProps(trackEvents,
- [
- {
- track: pc2.getTransceivers()[1].receiver.track,
- streams: [{id: stream3.id}]
- }
- ]);
-
- answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
-
- trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
- hasProps(trackEvents, []);
-
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- sender: {track: null},
- currentDirection: "recvonly"
- }
- ]);
-
- // Verify that we don't reuse the mid from the stopped transceiver
- const mid1 = pc2.getTransceivers()[0].mid;
- assert_not_equals(mid1, stoppedMid1);
-
- pc2.addTrack(track3, stream3);
- // There are two ways to handle this new track; reuse the recvonly
- // transceiver created above, or create a new transceiver and reuse the
- // disabled m-section. We're supposed to do the former.
- offer = await pc2.createOffer();
- assert_equals(offer.sdp.match(/m=/g).length, 2, "Exactly 2 m-lines in offer");
- assert_equals(offer.sdp.match(/m=audio 0 /g).length, 1,
- "One m-line is rejected, because the other was used");
-
- hasProps(pc2.getTransceivers(),
- [
- {
- mid: mid1,
- sender: {track: track3},
- currentDirection: "recvonly",
- direction: "sendrecv"
- }
- ]);
-
- // Add _another_ track; this should reuse the disabled m-section
- const stream4 = await getNoiseStream({audio: true});
- t.add_cleanup(() => stopTracks(stream4));
- const track4 = stream4.getAudioTracks()[0];
- pc2.addTrack(track4, stream4);
- offer = await pc2.createOffer();
- await pc2.setLocalDescription(offer);
- hasPropsAndUniqueMids(pc2.getTransceivers(),
- [
- {
- mid: mid1
- },
- {
- sender: {track: track4},
- }
- ]);
-
- // Fourth transceiver should have a new mid
- assert_not_equals(pc2.getTransceivers()[1].mid, stoppedMid0);
- assert_not_equals(pc2.getTransceivers()[1].mid, stoppedMid1);
-
- assert_equals(offer.sdp.match(/m=/g).length, 2,
- "Exactly 2 m-lines in offer, because m-section was reused");
- assert_equals(offer.sdp.match(/m=audio 0 /g), null,
- "No rejected m-line, because it was reused");
- };
-
- const checkStopAfterCreateOfferWithReusedMsection = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
-
- pc1.addTrack(audio, stream);
- pc1.addTrack(video, stream);
-
- await offerAnswer(pc1, pc2);
- pc1.getTransceivers()[1].stop();
- await offerAnswer(pc1, pc2);
-
- // Second (video) m-section has been negotiated disabled.
- const transceiver = pc1.addTransceiver("video");
- const offer = await pc1.createOffer();
- transceiver.stop();
- await pc1.setLocalDescription(offer);
- await pc2.setRemoteDescription(offer);
-
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- };
-
- const checkAddIceCandidateToStoppedTransceiver = async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream));
- const audio = stream.getAudioTracks()[0];
- const video = stream.getVideoTracks()[0];
-
- pc1.addTrack(audio, stream);
- pc1.addTrack(video, stream);
-
- pc2.addTrack(audio, stream);
- pc2.addTrack(video, stream);
-
- await pc1.setLocalDescription(await pc1.createOffer());
- pc1.getTransceivers()[1].stop();
- pc1.setLocalDescription({type: "rollback"});
-
- const offer = await pc2.createOffer();
- await pc2.setLocalDescription(offer);
- await pc1.setRemoteDescription(offer);
-
- await pc1.addIceCandidate(
- {
- candidate: "candidate:0 1 UDP 2122252543 192.168.1.112 64261 typ host",
- sdpMid: pc2.getTransceivers()[1].mid
- });
- };
-
-const tests = [
- checkAddTransceiverNoTrack,
- checkAddTransceiverWithTrack,
- checkAddTransceiverWithAddTrack,
- checkAddTransceiverWithDirection,
- //checkMsidNoTrackId,
- checkAddTransceiverWithSetRemoteOfferSending,
- checkAddTransceiverWithSetRemoteOfferNoSend,
- checkAddTransceiverBadKind,
- checkNoMidOffer,
- checkNoMidAnswer,
- checkSetDirection,
- //checkCurrentDirection,
- checkSendrecvWithNoSendTrack,
- checkSendrecvWithTracklessStream,
- checkAddTransceiverNoTrackDoesntPair,
- checkAddTransceiverWithTrackDoesntPair,
- checkAddTransceiverThenReplaceTrackDoesntPair,
- checkAddTransceiverThenAddTrackPairs,
- checkAddTrackPairs,
- checkReplaceTrackNullDoesntPreventPairing,
- checkRemoveAndReadd,
- checkAddTrackExistingTransceiverThenRemove,
- //checkRemoveTrackNegotiation,
- //checkMute,
- //checkStop,
- checkStopAfterCreateOffer,
- checkStopAfterSetLocalOffer,
- checkStopAfterSetRemoteOffer,
- checkStopAfterCreateAnswer,
- checkStopAfterSetLocalAnswer,
- checkStopAfterClose,
- checkLocalRollback,
- checkRollbackAndSetRemoteOfferWithDifferentType,
- //checkRemoteRollback,
- //checkMsectionReuse,
- checkStopAfterCreateOfferWithReusedMsection,
- checkAddIceCandidateToStoppedTransceiver,
- checkBundleTagRejected
-].forEach(test => promise_test(test, test.name));
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset="utf-8">
-<title>RTCSctpTransport constructor</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Test is based on the following revision:
-// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// generateDataChannelOffer()
-// generateAnswer()
-
-/*
- 6.1.
-
- partial interface RTCPeerConnection {
- readonly attribute RTCSctpTransport? sctp;
- ...
- };
-
- 6.1.1.
-
- interface RTCSctpTransport {
- readonly attribute RTCDtlsTransport transport;
- readonly attribute RTCSctpTransportState state;
- readonly attribute unrestricted double maxMessageSize;
- attribute EventHandler onstatechange;
- };
-
- 4.4.1.1. Constructor
- 9. Let connection have an [[SctpTransport]] internal slot, initialized to null.
-
- 4.4.1.6. Set the RTCSessionSessionDescription
- 2.2.6. If description is of type "answer" or "pranswer", then run the
- following steps:
- 1. If description initiates the establishment of a new SCTP association, as defined in
- [SCTP-SDP], Sections 10.3 and 10.4, create an RTCSctpTransport with an initial state
- of "connecting" and assign the result to the [[SctpTransport]] slot.
- */
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
-
- const offer = await generateAudioReceiveOnlyOffer(pc1);
- await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must remain null');
-}, 'setRemoteDescription() with answer not containing data media should not initialize pc.sctp');
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
-
- const offer = await generateAudioReceiveOnlyOffer(pc2);
- await Promise.all([pc2.setLocalDescription(offer), pc1.setRemoteDescription(offer)]);
- const answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must remain null');
-}, 'setLocalDescription() with answer not containing data media should not initialize pc.sctp');
-
-function validateSctpTransport(sctp) {
- assert_not_equals(sctp, null, 'RTCSctpTransport must be available');
-
- assert_true(sctp instanceof RTCSctpTransport,
- 'Expect pc.sctp to be instance of RTCSctpTransport');
-
- assert_true(sctp.transport instanceof RTCDtlsTransport,
- 'Expect sctp.transport to be instance of RTCDtlsTransport');
-
- assert_equals(sctp.state, 'connecting', 'RTCSctpTransport should be in the connecting state');
-
- // Note: Yes, Number.POSITIVE_INFINITY is also a 'number'
- assert_equals(typeof sctp.maxMessageSize, 'number',
- 'Expect sctp.maxMessageSize to be a number');
-}
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
-
- const offer = await generateDataChannelOffer(pc1);
- await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(answer);
-
- validateSctpTransport(pc1.sctp);
-}, 'setRemoteDescription() with answer containing data media should initialize pc.sctp');
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
-
- const offer = await generateDataChannelOffer(pc2);
- await Promise.all([pc2.setLocalDescription(offer), pc1.setRemoteDescription(offer)]);
- const answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
-
- validateSctpTransport(pc1.sctp);
-}, 'setLocalDescription() with answer containing data media should initialize pc.sctp');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCIceTransport</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('');
- assert_equals(null, pc1.sctp);
- assert_equals(null, pc2.sctp);
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- assert_not_equals(null, pc1.sctp);
- await pc2.setRemoteDescription(offer);
- assert_not_equals(null, pc2.sctp);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- // Since this test does not exchange candidates, state remains "connecting".
- assert_equals(pc1.sctp.state, "connecting");
- assert_equals(pc2.sctp.state, "connecting");
-}, 'SctpTransport objects are created at appropriate times');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- exchangeIceCandidates(pc1, pc2);
- pc1.createDataChannel('');
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- const pc1ConnectedWaiter = waitForState(pc1.sctp, 'connected');
- await pc2.setRemoteDescription(offer);
- const pc2ConnectedWaiter = waitForState(pc2.sctp, 'connected');
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- await pc1ConnectedWaiter;
- await pc2ConnectedWaiter;
- const pc1ClosedWaiter = waitForState(pc1.sctp, 'closed');
- const pc2ClosedWaiter = waitForState(pc2.sctp, 'closed');
- pc1.close();
- await pc1ClosedWaiter;
- await pc2ClosedWaiter;
-}, 'SctpTransport reaches connected and closed state');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCSctpTransport.prototype.maxChannels</title>
-<link rel="help" href="https://w3c.github.io/webrtc-pc/#rtcsctptransport-interface">
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async (t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
- pc.createDataChannel('test');
- const offer = await pc.createOffer();
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxChannels, null, 'maxChannels must not be set');
-}, 'An unconnected peerconnection must not have maxChannels set');
-
-promise_test(async (t) => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- exchangeIceCandidates(pc1, pc2);
- pc1.createDataChannel('');
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- const pc1ConnectedWaiter = waitForState(pc1.sctp, 'connected');
- await pc2.setRemoteDescription(offer);
- const pc2ConnectedWaiter = waitForState(pc2.sctp, 'connected');
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
- assert_equals(null, pc1.sctp.maxChannels);
- assert_equals(null, pc2.sctp.maxChannels);
- await pc1ConnectedWaiter;
- await pc2ConnectedWaiter;
- assert_not_equals(null, pc1.sctp.maxChannels);
- assert_not_equals(null, pc2.sctp.maxChannels);
- assert_equals(pc1.sctp.maxChannels, pc2.sctp.maxChannels);
-}, 'maxChannels gets instantiated after connecting');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCSctpTransport.prototype.maxMessageSize</title>
-<link rel="help" href="https://w3c.github.io/webrtc-pc/#rtcsctptransport-interface">
-<script src=../resources/testharness.js></script>
-<script src=../resources/testharnessreport.js></script>
-<script src="support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// This test has an assert_unreached() that requires that the variable
-// canSendSize (initiated below) must be 0 or greater than 2. The reason
-// is that we need two non-zero values for testing the following two cases:
-//
-// * if remote MMS `1` < canSendSize it should result in `1`.
-// * renegotiation of the above case with remoteMMS `2` should result in `2`.
-//
-// This is a bit unfortunate but shouldn't have any practical impact.
-
-// Helper class to read SDP attributes and generate SDPs with modified attribute values
-class SDPAttributeHelper {
- constructor(attrName, valueRegExpStr) {
- this.attrName = attrName;
- this.re = new RegExp(`^a=${attrName}:(${valueRegExpStr})\\r\\n`, 'm');
- }
-
- getValue(sdp) {
- const matches = sdp.match(this.re);
- return matches ? matches[1] : null;
- }
-
- sdpWithValue(sdp, value) {
- const matches = sdp.match(this.re);
- const sdpParts = sdp.split(matches[0]);
- const attributeLine = arguments.length > 1 ? `a=${this.attrName}:${value}\r\n` : '';
- return `${sdpParts[0]}${attributeLine}${sdpParts[1]}`;
- }
-
- sdpWithoutAttribute(sdp) {
- return this.sdpWithValue(sdp);
- }
-}
-
-const mmsAttributeHelper = new SDPAttributeHelper('max-message-size', '\\d+');
-let canSendSize = null;
-const remoteSize1 = 1;
-const remoteSize2 = 2;
-
-promise_test(async (t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
-
- let offer = await generateDataChannelOffer(pc);
- assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
- 'SDP should have max-message-size attribute');
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, 0) };
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- canSendSize = pc.sctp.maxMessageSize === Number.POSITIVE_INFINITY ? 0 : pc.sctp.maxMessageSize;
- if (canSendSize !== 0 && canSendSize < remoteSize2) {
- assert_unreached(
- 'This test needs canSendSize to be 0 or > 2 for further "below" and "above" tests');
- }
-}, 'Determine the local side send limitation (canSendSize) by offering a max-message-size of 0');
-
-promise_test(async (t) => {
- assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
-
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
-
- let offer = await generateDataChannelOffer(pc);
- assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
- 'SDP should have max-message-size attribute');
-
- // Remove the max-message-size SDP attribute
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithoutAttribute(offer.sdp) };
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- // Test outcome depends on canSendSize value
- if (canSendSize !== 0) {
- assert_equals(pc.sctp.maxMessageSize, Math.min(65536, canSendSize),
- 'Missing SDP attribute and a non-zero canSendSize should give an maxMessageSize of min(65536, canSendSize)');
- } else {
- assert_equals(pc.sctp.maxMessageSize, 65536,
- 'Missing SDP attribute and a canSendSize of 0 should give an maxMessageSize of 65536');
- }
-}, 'Remote offer SDP missing max-message-size attribute');
-
-promise_test(async (t) => {
- assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
-
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
-
- let offer = await generateDataChannelOffer(pc);
- assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
- 'SDP should have max-message-size attribute');
-
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1) };
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxMessageSize, remoteSize1,
- 'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
-}, 'max-message-size with a (non-zero) value provided by the remote peer');
-
-promise_test(async (t) => {
- assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
-
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
-
- let offer = await generateDataChannelOffer(pc);
- assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
- 'SDP should have max-message-size attribute');
-
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1) };
- await pc.setRemoteDescription(offer);
- let answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxMessageSize, remoteSize1,
- 'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
-
- // Start new O/A exchange that updates max-message-size to remoteSize2
- offer = await pc.createOffer();
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize2)};
- await pc.setRemoteDescription(offer);
- answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxMessageSize, remoteSize2,
- 'maxMessageSize should be the new value provided by the remote peer (as long as it is less than canSendSize)');
-
- // Start new O/A exchange that updates max-message-size to zero
- offer = await pc.createOffer();
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, 0)};
- await pc.setRemoteDescription(offer);
- answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxMessageSize, canSendSize,
- 'maxMessageSize should be canSendSize');
-
- // Start new O/A exchange that updates max-message-size to remoteSize1 again
- offer = await pc.createOffer();
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1)};
- await pc.setRemoteDescription(offer);
- answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- assert_equals(pc.sctp.maxMessageSize, remoteSize1,
- 'maxMessageSize should be the new value provided by the remote peer (as long as it is less than canSendSize)');
-}, 'Renegotiate max-message-size with various values provided by the remote peer');
-
-promise_test(async (t) => {
- assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
-
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
- const largerThanCanSendSize = canSendSize === 0 ? 0 : canSendSize + 1;
-
- let offer = await generateDataChannelOffer(pc);
- assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
- 'SDP should have max-message-size attribute');
-
- offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, largerThanCanSendSize) };
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- await pc.setLocalDescription(answer);
-
- assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
- // Test outcome depends on canSendSize value
- if (canSendSize !== 0) {
- assert_equals(pc.sctp.maxMessageSize, canSendSize,
- 'A remote value larger than a non-zero canSendSize should limit maxMessageSize to canSendSize');
- } else {
- assert_equals(pc.sctp.maxMessageSize, Number.POSITIVE_INFINITY,
- 'A remote value of zero and canSendSize zero should result in "infinity"');
- }
-}, 'max-message-size with a (non-zero) value larger than canSendSize provided by the remote peer');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCTrackEvent constructor</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
- 'use strict';
-
- // Test is based on the following editor draft:
- // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
- /*
- 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;
- };
-
- dictionary RTCTrackEventInit : EventInit {
- required RTCRtpReceiver receiver;
- required MediaStreamTrack track;
- sequence<MediaStream> streams = [];
- required RTCRtpTransceiver transceiver;
- };
- */
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
- const { track } = receiver;
-
- const trackEvent = new RTCTrackEvent('track', {
- receiver, track, transceiver
- });
-
- assert_equals(trackEvent.receiver, receiver);
- assert_equals(trackEvent.track, track);
- assert_array_equals(trackEvent.streams, []);
- assert_array_equals(trackEvent.streams, trackEvent.streams, '[SameObject]');
- assert_equals(trackEvent.transceiver, transceiver);
-
- assert_equals(trackEvent.type, 'track');
- assert_false(trackEvent.bubbles);
- assert_false(trackEvent.cancelable);
-
- }, `new RTCTrackEvent() with valid receiver, track, transceiver should succeed`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
- const { track } = receiver;
-
- const stream = new MediaStream([track]);
-
- const trackEvent = new RTCTrackEvent('track', {
- receiver, track, transceiver,
- streams: [stream]
- });
-
- assert_equals(trackEvent.receiver, receiver);
- assert_equals(trackEvent.track, track);
- assert_array_equals(trackEvent.streams, [stream]);
- assert_equals(trackEvent.transceiver, transceiver);
-
- }, `new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
- const { track } = receiver;
-
- const stream1 = new MediaStream([track]);
- const stream2 = new MediaStream([track]);
-
- const trackEvent = new RTCTrackEvent('track', {
- receiver, track, transceiver,
- streams: [stream1, stream2]
- });
-
- assert_equals(trackEvent.receiver, receiver);
- assert_equals(trackEvent.track, track);
- assert_array_equals(trackEvent.streams, [stream1, stream2]);
- assert_equals(trackEvent.transceiver, transceiver);
-
- }, `new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const receiver = pc.addTransceiver('audio').receiver;
- const track = pc.addTransceiver('audio').receiver.track;
-
- const stream = new MediaStream();
-
- const trackEvent = new RTCTrackEvent('track', {
- receiver, track, transceiver,
- streams: [stream]
- });
-
- assert_equals(trackEvent.receiver, receiver);
- assert_equals(trackEvent.track, track);
- assert_array_equals(trackEvent.streams, [stream]);
- assert_equals(trackEvent.transceiver, transceiver);
-
- }, `new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
- const { track } = receiver;
-
- assert_throws_js(TypeError, () =>
- new RTCTrackEvent('track', {
- receiver, track
- }));
-
- }, `new RTCTrackEvent() with no transceiver should throw TypeError`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
-
- assert_throws_js(TypeError, () =>
- new RTCTrackEvent('track', {
- receiver, transceiver
- }));
-
- }, `new RTCTrackEvent() with no track should throw TypeError`);
-
- test(t => {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { receiver } = transceiver;
- const { track } = receiver;
-
- assert_throws_js(TypeError, () =>
- new RTCTrackEvent('track', {
- track, transceiver
- }));
-
- }, `new RTCTrackEvent() with no receiver should throw TypeError`);
-
- /*
- Coverage Report
- Interface tests are counted as 1 trivial test
-
- Tested 1
- Total 1
- */
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>Change of msid in remote description should trigger related track events</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-const sdpBase =`v=0
-o=- 5511237691691746 2 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=group:BUNDLE 0
-a=ice-options:trickle
-a=ice-lite
-a=msid-semantic:WMS *
-m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 102 0 8 105 13 110 113 126
-c=IN IP6 ::
-a=rtcp:9 IN IP6 ::
-a=rtcp-mux
-a=mid:0
-a=sendrecv
-a=ice-ufrag:z0i8R3C9C4hPRWls
-a=ice-pwd:O7bPpOFAqasqoidV4yxnFVbc
-a=ice-lite
-a=fingerprint:sha-256 B7:9C:0D:C9:D1:42:57:97:82:4D:F9:B7:93:75:49:C3:42:21:5A:DD:9C:B5:ED:53:53:F0:B4:C8:AE:88:7A:E7
-a=setup:actpass
-a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
-a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
-a=rtpmap:0 PCMU/8000`;
-
-const sdp0 = sdpBase + `
-`;
-
-const sdp1 = sdpBase + `
-a=msid:1 2
-a=ssrc:3 cname:4
-a=ssrc:3 msid:1 2
-`;
-
-const sdp2 = sdpBase + `
-a=ssrc:3 cname:4
-a=ssrc:3 msid:1 2
-`;
-
-const sdp3 = sdpBase + `
-a=msid:1 2
-a=ssrc:3 cname:4
-a=ssrc:3 msid:3 2
-`;
-
-const sdp4 = sdp1.replace('msid-semantic', 'unknownattr');
-
-const sdp5 = sdpBase + `
-a=msid:-
-`;
-
-const sdp6 = sdpBase + `
-a=msid:1 2
-a=msid:1 2
-`;
-
-async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
-{
- const testTrackPromise = new Promise(resolve => {
- pc.ontrack = (event) => { resolve([event.track, event.streams]); };
- });
- await pc.setRemoteDescription({type: 'offer', sdp: sdp});
- return testTrackPromise;
-}
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
- assert_equals(streams.length, 1, "track event has a stream");
-}, "When a=msid is absent, the track should still be associated with a stream");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
- assert_equals(streams.length, 1, "track event has a stream");
- assert_equals(streams[0].id, "1", "msid should match");
-}, "Source-level msid should be ignored if media-level msid is present");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp2);
- assert_equals(streams.length, 1, "track event has a stream");
- assert_equals(streams[0].id, "1", "msid should match");
-}, "Source-level msid should be parsed if media-level msid is absent");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- let track;
- let streams;
- try {
- [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp3);
- } catch (e) {
- return;
- }
- assert_equals(streams.length, 1, "track event has a stream");
- assert_equals(streams[0].id, "1", "msid should match");
-}, "Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp4);
- assert_equals(streams.length, 1, "track event has a stream");
- assert_equals(streams[0].id, "1", "msid should match");
-}, "stream ids should be found even if msid-semantic is absent");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
- assert_equals(streams.length, 1, "track event has a stream");
- assert_equals(streams[0].id, "1", "msid should match");
- const stream = streams[0];
-
- await pc.setLocalDescription(await pc.createAnswer());
-
- const testTrackPromise = new Promise((resolve) => { stream.onremovetrack = resolve; });
- await pc.setRemoteDescription({type: 'offer', 'sdp': sdp0});
- await testTrackPromise;
-
- assert_equals(stream.getAudioTracks().length, 0, "stream should be empty");
-}, "Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream");
-
-promise_test(async test => {
- const pc = new RTCPeerConnection();
- test.add_cleanup(() => pc.close());
-
- let [track0, streams0] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
-
- await pc.setLocalDescription(await pc.createAnswer());
-
- let [track1, streams1] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
-
- assert_equals(streams1.length, 1, "track event has a stream");
- assert_equals(streams1[0].id, "1", "msid should match");
- assert_equals(streams1[0].getTracks()[0], track0, "track should match");
-}, "Applying a remote description with a new msid should trigger firing an event with populated streams");
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-['audio', 'video'].forEach((kind) => {
- // Make sure "ontrack" fires if a prevuously rolled back track is added back.
- promise_test(async t => {
- const constraints = {};
- constraints[kind] = true;
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
-
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(track, stream);
- pc2.addTrack(track, stream);
- const [pc1Transceiver] = pc1.getTransceivers();
- const [pc2Transceiver] = pc2.getTransceivers();
-
- let remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
-
- // Apply remote offer, but don't complete the entire exchange.
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- // The addTrack-transceiver gets associated, no need for a second
- // transceiver.
- assert_equals(pc2.getTransceivers().length, 1);
- const remoteStream = await remoteStreamViaOnTrackPromise;
- assert_equals(remoteStream.id, stream.id);
-
- const onRemoveTrackPromise = new Promise(r => {
- remoteStream.onremovetrack = () => { r(); };
- });
-
- // Cause track removal due to rollback.
- await pc2.setLocalDescription({type:'rollback'});
- // The track was removed.
- await onRemoveTrackPromise;
-
- // Sanity check that ontrack still fires if we add it back again by applying
- // the same remote offer.
- remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
- await pc2.setRemoteDescription(pc1.localDescription);
- const revivedRemoteStream = await remoteStreamViaOnTrackPromise;
- // This test only expects IDs to be the same. The same stream object should
- // also be used, but this should be covered by separate tests.
- // TODO(https://crbug.com/1321738): Add MediaStream identity tests.
- assert_equals(remoteStream.id, revivedRemoteStream.id);
- // No cheating, the same transciever should be used as before.
- assert_equals(pc2.getTransceivers().length, 1);
- }, `[${kind}] Track with stream: removal due to disassociation in rollback and then add it back again`);
-
- // This is the same test as above, but this time without any remote streams.
- // This test could fail if [[FiredDirection]] was not reset in a rollback but
- // the above version of the test might still pass due to the track being
- // re-added to its stream.
- promise_test(async t => {
- const constraints = {};
- constraints[kind] = true;
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
-
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(track);
- pc2.addTrack(track);
- const [pc1Transceiver] = pc1.getTransceivers();
- const [pc2Transceiver] = pc2.getTransceivers();
-
- let remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
-
- // Apply remote offer, but don't complete the entire exchange.
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- // The addTrack-transceiver gets associated, no need for a second
- // transceiver.
- assert_equals(pc2.getTransceivers().length, 1);
- const remoteTrack = await remoteTrackPromise;
- assert_not_equals(remoteTrack, null);
-
- // Cause track removal due to rollback.
- await pc2.setLocalDescription({type:'rollback'});
- // There's nothing equivalent to stream.onremovetrack when you don't have a
- // stream, but the track should become muted (if it isn't already).
- if (!remoteTrack.muted) {
- await new Promise(r => remoteTrack.onmute = () => { r(); });
- }
- assert_equals(remoteTrack.muted, true);
-
- // Sanity check that ontrack still fires if we add it back again by applying
- // the same remote offer.
- remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
- await pc2.setRemoteDescription(pc1.localDescription);
- const revivedRemoteTrack = await remoteTrackPromise;
- // We can be sure the same track is used, because the same transceiver is
- // used (and transciever.receiver.track has same lifetime as transceiver).
- assert_equals(pc2.getTransceivers().length, 1);
- assert_equals(remoteTrack, revivedRemoteTrack);
- }, `[${kind}] Track without stream: removal due to disassociation in rollback and then add it back`);
-
- // Make sure "ontrack" can fire in a rollback (undo making it inactive).
- promise_test(async t => {
- const constraints = {};
- constraints[kind] = true;
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
-
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(track, stream);
- const [pc1Transceiver] = pc1.getTransceivers();
-
- let remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
-
- // Complete O/A exchange such that the transceiver gets associated.
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
- const [pc2Transceiver] = pc2.getTransceivers();
- assert_equals(pc2Transceiver.direction, 'recvonly');
- assert_equals(pc2Transceiver.currentDirection, 'recvonly');
-
- const remoteStream = await remoteStreamViaOnTrackPromise;
- assert_equals(remoteStream.id, stream.id);
- const onRemoveTrackPromise = new Promise(r => {
- remoteStream.onremovetrack = () => { r(); };
- });
-
- // Cause track removal.
- pc1Transceiver.direction = 'inactive';
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- // The track was removed.
- await onRemoveTrackPromise;
-
- // Rolling back the offer revives the track, causing ontrack to fire again.
- remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
- await pc2.setLocalDescription({type:'rollback'});
- const revivedRemoteStream = await remoteStreamViaOnTrackPromise;
- // This test only expects IDs to be the same. The same stream object should
- // also be used, but this should be covered by separate tests.
- // TODO(https://crbug.com/1321738): Add MediaStream identity tests.
- assert_equals(remoteStream.id, revivedRemoteStream.id);
- }, `[${kind}] Track with stream: removal due to direction changing and then add back using rollback`);
-
- // Same test as above but without remote streams.
- promise_test(async t => {
- const constraints = {};
- constraints[kind] = true;
- const stream = await navigator.mediaDevices.getUserMedia(constraints);
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
-
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- pc1.addTrack(track);
- const [pc1Transceiver] = pc1.getTransceivers();
-
- let remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
-
- // Complete O/A exchange such that the transceiver gets associated.
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
- const [pc2Transceiver] = pc2.getTransceivers();
- assert_equals(pc2Transceiver.direction, 'recvonly');
- assert_equals(pc2Transceiver.currentDirection, 'recvonly');
-
- const remoteTrack = await remoteTrackPromise;
-
- // Cause track removal.
- pc1Transceiver.direction = 'inactive';
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- // There's nothing equivalent to stream.onremovetrack when you don't have a
- // stream, but the track should become muted (if it isn't already).
- if (!remoteTrack.muted) {
- await new Promise(r => remoteTrack.onmute = () => { r(); });
- }
- assert_equals(remoteTrack.muted, true);
-
- // Rolling back the offer revives the track, causing ontrack to fire again.
- remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
- await pc2.setLocalDescription({type:'rollback'});
- const revivedRemoteTrack = await remoteTrackPromise;
- // We can be sure the same track is used, because the same transceiver is
- // used (and transciever.receiver.track has same lifetime as transceiver).
- assert_equals(pc2.getTransceivers().length, 1);
- assert_equals(remoteTrack, revivedRemoteTrack);
- }, `[${kind}] Track without stream: removal due to direction changing and then add back using rollback`);
-});
-
-function getTrackViaOnTrackPromise(pc) {
- return new Promise(r => {
- pc.ontrack = e => {
- pc.ontrack = null;
- r(e.track);
- };
- });
-}
-
-function getRemoteStreamViaOnTrackPromise(pc) {
- return new Promise(r => {
- pc.ontrack = e => {
- pc.ontrack = null;
- r(e.streams[0]);
- };
- });
-}
-
-</script>
+++ /dev/null
-Coverage is based on the following editor draft:
-https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-7. insertDTMF
-
- [Trivial]
- - The tones parameter is treated as a series of characters.
-
- [RTCDTMFSender-insertDTMF]
- - The characters 0 through 9, A through D, #, and * generate the associated
- DTMF tones.
-
- [RTCDTMFSender-insertDTMF]
- - The characters a to d MUST be normalized to uppercase on entry and are equivalent
- to A to D.
-
- [RTCDTMFSender-insertDTMF]
- - As noted in [RTCWEB-AUDIO] Section 3, support for the characters 0 through 9,
- A through D, #, and * are required.
-
- [RTCDTMFSender-insertDTMF]
- - The character ',' MUST be supported, and indicates a delay of 2 seconds before
- processing the next character in the tones parameter.
-
- [RTCDTMFSender-insertDTMF]
- - All other characters (and only those other characters) MUST
- be considered unrecognized.
-
- [Trivial]
- - The duration parameter indicates the duration in ms to use for each character passed
- in the tones parameters.
-
- [RTCDTMFSender-ontonechange]
- - The duration cannot be more than 6000 ms or less than 40 ms.
-
- [RTCDTMFSender-ontonechange]
- - The default duration is 100 ms for each tone.
-
- [RTCDTMFSender-ontonechange]
- - The interToneGap parameter indicates the gap between tones in ms. The user agent
- clamps it to at least 30 ms. The default value is 70 ms.
-
- [Untestable]
- - The browser MAY increase the duration and interToneGap times to cause the times
- that DTMF start and stop to align with the boundaries of RTP packets but it MUST
- not increase either of them by more than the duration of a single RTP audio packet.
-
- [Trivial]
- When the insertDTMF() method is invoked, the user agent MUST run the following steps:
-
- [Trivial]
- 1. let sender be the RTCRtpSender used to send DTMF.
-
- [Trivial]
- 2. Let transceiver be the RTCRtpTransceiver object associated with sender.
-
- [RTCDTMFSender-insertDTMF]
- 3. If transceiver.stopped is true, throw an InvalidStateError.
-
- [RTCDTMFSender-insertDTMF]
- 4. If transceiver.currentDirection is recvonly or inactive, throw an
- InvalidStateError.
-
- [Trivial]
- 5. Let tones be the method's first argument.
-
- [RTCDTMFSender-insertDTMF]
- 6. If tones contains any unrecognized characters, throw an InvalidCharacterError.
-
- [RTCDTMFSender-insertDTMF]
- 7. Set the object's toneBuffer attribute to tones.
-
- [RTCDTMFSender-ontonechange]
- 8. If the value of the duration parameter is less than 40, set it to 40.
-
- [RTCDTMFSender-ontonechange-long]
- If, on the other hand, the value is greater than 6000, set it to 6000.
-
- [RTCDTMFSender-ontonechange]
- 9. If the value of the interToneGap parameter is less than 30, set it to 30.
-
- [RTCDTMFSender-ontonechange]
- 10. If toneBuffer is an empty string, abort these steps.
-
- [RTCDTMFSender-ontonechange]
- 11. If a Playout task is scheduled to be run; abort these steps;
-
- [RTCDTMFSender-ontonechange]
- otherwise queue a task that runs the following steps (Playout task):
-
- [RTCDTMFSender-ontonechange]
- 1. If transceiver.stopped is true, abort these steps.
-
- [RTCDTMFSender-ontonechange]
- 2. If transceiver.currentDirection is recvonly or inactive, abort these steps.
-
- [RTCDTMFSender-ontonechange]
- 3. If toneBuffer is an empty string, fire an event named tonechange with an
- empty string at the RTCDTMFSender object and abort these steps.
-
- [RTCDTMFSender-ontonechange]
- 4. Remove the first character from toneBuffer and let that character be tone.
-
- [Untestable]
- 5. Start playout of tone for duration ms on the associated RTP media stream,
- using the appropriate codec.
-
- [RTCDTMFSender-ontonechange]
- 6. Queue a task to be executed in duration + interToneGap ms from now that
- runs the steps labelled Playout task.
-
- [RTCDTMFSender-ontonechange]
- 7. Fire an event named tonechange with a string consisting of tone at the
- RTCDTMFSender object.
-
-Coverage Report
-
- Tested 31
- Not Tested 0
- Untestable 1
-
- Total 32
+++ /dev/null
-Coverage is based on the following editor draft:
-https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-9.3 Requesting Identity Assertions
-
- [Trivial]
- The identity assertion request process is triggered by a call to createOffer,
- createAnswer, or getIdentityAssertion. When these calls are invoked and an
- identity provider has been set, the following steps are executed:
-
- [RTCPeerConnection-getIdentityAssertion]
- 1. The RTCPeerConnection instantiates an IdP as described in Identity Provider
- Selection and Registering an IdP Proxy. If the IdP cannot be loaded, instantiated,
- or the IdP proxy is not registered, this process fails.
-
- [RTCPeerConnection-getIdentityAssertion]
- 2. The RTCPeerConnection invokes the generateAssertion method on the
- RTCIdentityProvider methods registered by the IdP.
-
- [RTCPeerConnection-getIdentityAssertion]
- The RTCPeerConnection generates the contents parameter to this method as
- described in [RTCWEB-SECURITY-ARCH]. The value of contents includes the
- fingerprint of the certificate that was selected or generated during the
- construction of the RTCPeerConnection. The origin parameter contains the
- origin of the script that calls the RTCPeerConnection method that triggers
- this behavior. The usernameHint value is the same value that is provided
- to setIdentityProvider, if any such value was provided.
-
- [RTCPeerConnection-getIdentityAssertion]
- 3. The IdP proxy returns a Promise to the RTCPeerConnection. The IdP proxy is
- expected to generate the identity assertion asynchronously.
-
- [RTCPeerConnection-getIdentityAssertion]
- If the user has been authenticated by the IdP, and the IdP is able to generate
- an identity assertion, the IdP resolves the promise with an identity assertion
- in the form of an RTCIdentityAssertionResult .
-
- [RTCPeerConnection-getIdentityAssertion]
- This step depends entirely on the IdP. The methods by which an IdP authenticates
- users or generates assertions is not specified, though they could involve
- interacting with the IdP server or other servers.
-
- [RTCPeerConnection-getIdentityAssertion]
- 4. If the IdP proxy produces an error or returns a promise that does not resolve
- to a valid RTCIdentityValidationResult (see 9.5 IdP Error Handling), then
- identity validation fails.
-
- [Untestable]
- 5. The RTCPeerConnection MAY store the identity assertion for use with future
- offers or answers. If a fresh identity assertion is needed for any reason,
- applications can create a new RTCPeerConnection.
-
- [RTCPeerConnection-getIdentityAssertion]
- 6. If the identity request was triggered by a createOffer() or createAnswer(),
- then the assertion is converted to a JSON string, base64-encoded and inserted
- into an a=identity attribute in the session description.
-
- [RTCPeerConnection-getIdentityAssertion]
- If assertion generation fails, then the promise for the corresponding function call
- is rejected with a newly created OperationError.
-
-9.3.1 User Login Procedure
- [RTCPeerConnection-getIdentityAssertion]
- An IdP MAY reject an attempt to generate an identity assertion if it is unable to
- verify that a user is authenticated. This might be due to the IdP not having the
- necessary authentication information available to it (such as cookies).
-
- [RTCPeerConnection-getIdentityAssertion]
- Rejecting the promise returned by generateAssertion will cause the error to propagate
- to the application. Login errors are indicated by rejecting the promise with an RTCError
- with errorDetail set to "idp-need-login".
-
- [RTCPeerConnection-getIdentityAssertion]
- The URL to login at will be passed to the application in the idpLoginUrl attribute of
- the RTCPeerConnection.
-
- [Out of Scope]
- An application can load the login URL in an IFRAME or popup window; the resulting page
- then SHOULD provide the user with an opportunity to enter any information necessary to
- complete the authorization process.
-
- [Out of Scope]
- Once the authorization process is complete, the page loaded in the IFRAME or popup sends
- a message using postMessage [webmessaging] to the page that loaded it (through the
- window.opener attribute for popups, or through window.parent for pages loaded in an IFRAME).
- The message MUST consist of the DOMString "LOGINDONE". This message informs the application
- that another attempt at generating an identity assertion is likely to be successful.
-
-9.4. Verifying Identity Assertions
- The identity assertion request process involves the following asynchronous steps:
-
- [TODO]
- 1. The RTCPeerConnection awaits any prior identity validation. Only one identity
- validation can run at a time for an RTCPeerConnection. This can happen because
- the resolution of setRemoteDescription is not blocked by identity validation
- unless there is a target peer identity.
-
- [RTCPeerConnection-peerIdentity]
- 2. The RTCPeerConnection loads the identity assertion from the session description
- and decodes the base64 value, then parses the resulting JSON. The idp parameter
- of the resulting dictionary contains a domain and an optional protocol value
- that identifies the IdP, as described in [RTCWEB-SECURITY-ARCH].
-
- [RTCPeerConnection-peerIdentity]
- 3. The RTCPeerConnection instantiates the identified IdP as described in 9.1.1
- Identity Provider Selection and 9.2 Registering an IdP Proxy. If the IdP
- cannot be loaded, instantiated or the IdP proxy is not registered, this
- process fails.
-
- [RTCPeerConnection-peerIdentity]
- 4. The RTCPeerConnection invokes the validateAssertion method registered by the IdP.
-
- [RTCPeerConnection-peerIdentity]
- The assertion parameter is taken from the decoded identity assertion. The origin
- parameter contains the origin of the script that calls the RTCPeerConnection
- method that triggers this behavior.
-
- [RTCPeerConnection-peerIdentity]
- 5. The IdP proxy returns a promise and performs the validation process asynchronously.
-
- [Out of Scope]
- The IdP proxy verifies the identity assertion using whatever means necessary.
- Depending on the authentication protocol this could involve interacting with the
- IdP server.
-
- [RTCPeerConnection-peerIdentity]
- 6. If the IdP proxy produces an error or returns a promise that does not resolve
- to a valid RTCIdentityValidationResult (see 9.5 IdP Error Handling), then
- identity validation fails.
-
- [RTCPeerConnection-peerIdentity]
- 7. Once the assertion is successfully verified, the IdP proxy resolves the promise
- with an RTCIdentityValidationResult containing the validated identity and the
- original contents that are the payload of the assertion.
-
- [RTCPeerConnection-peerIdentity]
- 8. The RTCPeerConnection decodes the contents and validates that it contains a
- fingerprint value for every a=fingerprint attribute in the session description.
- This ensures that the certificate used by the remote peer for communications
- is covered by the identity assertion.
-
- [RTCPeerConnection-peerIdentity]
- 9. The RTCPeerConnection validates that the domain portion of the identity matches
- the domain of the IdP as described in [RTCWEB-SECURITY-ARCH]. If this check fails
- then the identity validation fails.
-
- [RTCPeerConnection-peerIdentity]
- 10. The RTCPeerConnection resolves the peerIdentity attribute with a new instance
- of RTCIdentityAssertion that includes the IdP domain and peer identity.
-
- [Out of Scope]
- 11. The user agent MAY display identity information to a user in its UI. Any user
- identity information that is displayed in this fashion MUST use a mechanism that
- cannot be spoofed by content.
-
- [RTCPeerConnection-peerIdentity]
- If identity validation fails, the peerIdentity promise is rejected with a newly
- created OperationError.
-
- [RTCPeerConnection-peerIdentity]
- If identity validation fails and there is a target peer identity for the
- RTCPeerConnection, the promise returned by setRemoteDescription MUST be rejected
- with the same DOMException.
-
-9.5. IdP Error Handling
- [RTCPeerConnection-getIdentityAssertion]
- - A RTCPeerConnection might be configured with an identity provider, but loading of
- the IdP URI fails. Any procedure that attempts to invoke such an identity provider
- and cannot load the URI fails with an RTCError with errorDetail set to
- "idp-load-failure" and the httpRequestStatusCode attribute of the error set to the
- HTTP status code of the response.
-
- [Untestable]
- - If the IdP loads fails due to the TLS certificate used for the HTTPS connection not
- being trusted, it fails with an RTCError with errorDetail set to "idp-tls-failure".
- This typically happens when the IdP uses certificate pinning and an intermediary
- such as an enterprise firewall has intercepted the TLS connection.
-
- [RTCPeerConnection-getIdentityAssertion]
- - If the script loaded from the identity provider is not valid JavaScript or does not
- implement the correct interfaces, it causes an IdP failure with an RTCError with
- errorDetail set to "idp-bad-script-failure".
-
- [TODO]
- - An apparently valid identity provider might fail in several ways.
-
- If the IdP token has expired, then the IdP MUST fail with an RTCError with
- errorDetail set to "idp-token-expired".
-
- If the IdP token is not valid, then the IdP MUST fail with an RTCError with
- errorDetail set to "idp-token-invalid".
-
- [Untestable]
- - The user agent SHOULD limit the time that it allows for an IdP to 15 seconds.
- This includes both the loading of the IdP proxy and the identity assertion
- generation or validation. Failure to do so potentially causes the corresponding
- operation to take an indefinite amount of time. This timer can be cancelled when
- the IdP proxy produces a response. Expiration of this timer cases an IdP failure
- with an RTCError with errorDetail set to "idp-timeout".
-
- [RTCPeerConnection-getIdentityAssertion]
- - If the identity provider requires the user to login, the operation will fail
- RTCError with errorDetail set to "idp-need-login" and the idpLoginUrl attribute
- of the error set to the URL that can be used to login.
-
- [RTCPeerConnection-peerIdentity]
- - Even when the IdP proxy produces a positive result, the procedure that uses this
- information might still fail. Additional validation of a RTCIdentityValidationResult
- value is still necessary. The procedure for validation of identity assertions
- describes additional steps that are required to successfully validate the output
- of the IdP proxy.
-
-
-Coverage Report
-
- Tested 29
- Not Tested 2
- Untestable 4
-
- Total 35
+++ /dev/null
-Coverage Report is based on the following editor draft:
-https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-4.3.1.6 Set the RTCSessionSessionDescription
-
- [Trivial]
- 1. Let p be a new promise.
-
- [Trivial]
- 2. In parallel, start the process to apply description as described in [JSEP]
- (section 5.5. and section 5.6.).
-
- [Trivial]
- 1. If the process to apply description fails for any reason, then user agent
- MUST queue a task that runs the following steps:
-
- [Untestable]
- 1. If connection's [[IsClosed]] slot is true, then abort these steps.
-
- [Untestable]
- 2. If elements of the SDP were modified, then reject p with a newly created
- InvalidModificationError and abort these steps.
-
- [RTCPeerConnection-setLocalDescription-answer]
- [RTCPeerConnection-setRemoteDescription-offer]
- [RTCPeerConnection-setRemoteDescription-answer]
- 3. If the description's type is invalid for the current signaling state of
- connection as described in [JSEP] (section 5.5. and section 5.6.), then
- reject p with a newly created InvalidStateError and abort these steps.
-
- [RTCPeerConnection-setRemoteDescription-offer]
- 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 error was detected) and abort these steps.
-
- [Untestable]
- 5. If the content of description is invalid, then reject p with a newly
- created InvalidAccessError and abort these steps.
-
- [Untestable]
- 6. For all other errors, for example if description cannot be applied at
- the media layer, reject p with a newly created OperationError.
-
- [Trivial]
- 2. If description is applied successfully, the user agent MUST queue a task
- that runs the following steps:
-
- [Untestable]
- 1. If connection's [[isClosed]] slot is true, then abort these steps.
-
- [RTCPeerConnection-setLocalDescription]
- 2. If description is set as a local description, then run one of the
- following steps:
-
- [RTCPeerConnection-setLocalDescription-offer]
- - If description is of type "offer", set connection.pendingLocalDescription
- to description and signaling state to have-local-offer.
-
- [RTCPeerConnection-setLocalDescription-answer]
- - If description is of type "answer", then this completes an offer answer
- negotiation.
-
- Set connection's currentLocalDescription to description and
- currentRemoteDescription to the value of pendingRemoteDescription.
-
- Set both pendingRemoteDescription and pendingLocalDescription to null.
- Finally set connection's signaling state to stable
-
- [RTCPeerConnection-setLocalDescription-rollback]
- - If description is of type "rollback", then this is a rollback. Set
- connection.pendingLocalDescription to null and signaling state to stable.
-
- [RTCPeerConnection-setLocalDescription-pranswer]
- - If description is of type "pranswer", then set
- connection.pendingLocalDescription to description and signaling state to
- have-local-pranswer.
-
- [RTCPeerConnection-setRemoteDescription]
- 3. Otherwise, if description is set as a remote description, then run one of the
- following steps:
-
- [RTCPeerConnection-setRemoteDescription-offer]
- - If description is of type "offer", set connection.pendingRemoteDescription
- attribute to description and signaling state to have-remote-offer.
-
- [RTCPeerConnection-setRemoteDescription-answer]
- - If description is of type "answer", then this completes an offer answer
- negotiation.
-
- Set connection's currentRemoteDescription to description and
- currentLocalDescription to the value of pendingLocalDescription.
-
- Set both pendingRemoteDescription and pendingLocalDescription to null.
-
- Finally setconnection's signaling state to stable
-
- [RTCPeerConnection-setRemoteDescription-rollback]
- - If description is of type "rollback", then this is a rollback.
- Set connection.pendingRemoteDescription to null and signaling state to stable.
-
- [RTCPeerConnection-setRemoteDescription-rollback]
- - If description is of type "pranswer", then set
- connection.pendingRemoteDescription to description and signaling state
- to have-remote-pranswer.
-
- [RTCPeerConnection-setLocalDescription]
- [RTCPeerConnection-setRemoteDescription]
- 4. If connection's signaling state changed above, fire a simple event named
- signalingstatechange at connection.
-
- [TODO]
- 5. If description is of type "answer", and it initiates the closure of an existing
- SCTP association, as defined in [SCTP-SDP], Sections 10.3 and 10.4, set the value
- of connection's [[sctpTransport]] internal slot to null.
-
- [RTCSctpTransport]
- 6. If description is of type "answer" or "pranswer", then run the following steps:
-
- [RTCSctpTransport]
- 1. If description initiates the establishment of a new SCTP association,
- as defined in [SCTP-SDP], Sections 10.3 and 10.4, set the value of connection's
- [[sctpTransport]] internal slot to a newly created RTCSctpTransport.
-
- [TODO]
- 2. If description negotiates the DTLS role of the SCTP transport, and there is an
- RTCDataChannel with a null id, then generate an ID according to
- [RTCWEB-DATA-PROTOCOL].
-
- [Untestable]
- If no available ID could be generated, then run the following steps:
-
- [Untestable]
- 1. Let channel be the RTCDataChannel object for which an ID could not be
- generated.
-
- [Untestable]
- 2. Set channel's readyState attribute to closed.
-
- [Untestable]
- 3. Fire an event named error with a ResourceInUse exception at channel.
-
- [Untestable]
- 4. Fire a simple event named close at channel.
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 7. If description is set as a local description, then run the following steps for
- each media description in description that is not yet associated with an
- RTCRtpTransceiver object:
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 1. Let transceiver be the RTCRtpTransceiver used to create the media
- description.
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 2. Set transceiver's mid value to the mid of the corresponding media
- description.
-
- [RTCPeerConnection-ontrack]
- 8. If description is set as a remote description, then run the following steps
- for each media description in description:
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 1. As described by [JSEP] (section 5.9.), attempt to find an existing
- RTCRtpTransceiver object, transceiver, to represent the media description.
-
- [RTCPeerConnection-ontrack]
- 2. If no suitable transceiver is found (transceiver is unset), run the following
- steps:
-
- [RTCPeerConnection-ontrack]
- 1. Create an RTCRtpSender, sender, from the media description.
-
- [RTCPeerConnection-ontrack]
- 2. Create an RTCRtpReceiver, receiver, from the media description.
-
- [RTCPeerConnection-ontrack]
- 3. Create an RTCRtpTransceiver with sender, receiver and direction, and let
- transceiver be the result.
-
- [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.).
-
- [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.
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 5. If the media description is rejected, and transceiver is not already stopped,
- stop the RTCRtpTransceiver transceiver.
-
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 9. If description is of type "rollback", then run the following steps:
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 1. If the mid value of an RTCRtpTransceiver was set to a non-null value by
- the RTCSessionDescription that is being rolled back, set the mid value
- of that transceiver to null, as described by [JSEP] (section 4.1.8.2.).
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 2. If an RTCRtpTransceiver was created by applying the RTCSessionDescription
- that is being rolled back, and a track has not been attached to it via
- addTrack, remove that transceiver from connection's set of transceivers,
- as described by [JSEP] (section 4.1.8.2.).
-
- [TODO RTCPeerConnection-setDescription-transceiver]
- 3. Restore the value of connection's [[SctpTransport]] internal slot to its
- value at the last stable signaling state.
-
- [RTCPeerConnection-onnegotiationneeded]
- 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:
-
- [Untestable]
- 1. If connection's [[IsClosed]] slot is true, abort these steps.
-
- [RTCPeerConnection-onnegotiationneeded]
- 2. If connection's [[NegotiationNeeded]] slot is false, abort these steps.
-
- [RTCPeerConnection-onnegotiationneeded]
- 3. Fire a simple event named negotiationneeded at connection.
-
- [Trivial]
- 11. Resolve p with undefined.
-
- [Trivial]
- 3. Return p.
-
-
-Coverage Report
-
- Tested 35
- Not Tested 15
- Untestable 8
- Total 58
+++ /dev/null
-<!doctype html>
-<!--
-This test uses data only, and thus does not require fake media devices.
--->
-
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection GetStats</title>
-</head>
-<body>
- <div id="log"></div>
- <h2>Retrieved stats info</h2>
- <pre>
- <input type="button" onclick="showStats()" value="Show stats"></input>
- <div id="stats">
- </div>
- </pre>
-
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script type="text/javascript">
- var test = async_test('Can get stats from a basic WebRTC call.');
- var statsToShow;
- var gFirstConnection = null;
- var gSecondConnection = null;
-
- var onIceCandidateToFirst = test.step_func(function(event) {
- gSecondConnection.addIceCandidate(event.candidate);
- });
-
- var onIceCandidateToSecond = test.step_func(function(event) {
- gFirstConnection.addIceCandidate(event.candidate);
- });
-
- var getStatsRecordByType = function(stats, type) {
- for (let stat of stats.values()) {
- if (stat.type == type) {
- return stat;
- }
- }
- return null;
- }
-
- var onIceConnectionStateChange = test.step_func(function(event) {
- // Wait until connection is established.
- // Note - not all browsers reach 'completed' state, so we're
- // checking for 'connected' state instead.
- if (gFirstConnection.iceConnectionState != 'connected') {
- return;
- }
- gFirstConnection.getStats()
- .then(function(report) {
- let reportDictionary = {};
- for (let stats of report.values()) {
- reportDictionary[stats.id] = stats;
- }
- statsToShow = JSON.stringify(reportDictionary, null, 2);
- // Check the stats properties.
- assert_not_equals(report, null, 'No report');
- let sessionStat = getStatsRecordByType(report, 'peer-connection');
- assert_not_equals(sessionStat, null, 'Did not find peer-connection stats');
- assert_own_property(sessionStat, 'dataChannelsOpened', 'no dataChannelsOpened stat');
- // Once every 4000 or so tests, the datachannel won't be opened when the getStats
- // function is done, so allow both 0 and 1 datachannels.
- assert_true(sessionStat.dataChannelsOpened == 1 || sessionStat.dataChannelsOpened == 0,
- 'dataChannelsOpened count wrong');
- test.done();
- })
- .catch(test.step_func(function(e) {
- assert_unreached(e.name + ': ' + e.message + ': ');
- }));
- });
-
- // This function starts the test.
- test.step(function() {
- gFirstConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gFirstConnection.close());
- gFirstConnection.onicecandidate = onIceCandidateToFirst;
- gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
-
- gSecondConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gSecondConnection.close());
- gSecondConnection.onicecandidate = onIceCandidateToSecond;
-
- // The createDataChannel is necessary and sufficient to make
- // sure the ICE connection be attempted.
- gFirstConnection.createDataChannel('channel');
- var atStep = 'Create offer';
-
- gFirstConnection.createOffer()
- .then(function(offer) {
- atStep = 'Set local description at first';
- return gFirstConnection.setLocalDescription(offer);
- })
- .then(function() {
- atStep = 'Set remote description at second';
- return gSecondConnection.setRemoteDescription(
- gFirstConnection.localDescription);
- })
- .then(function() {
- atStep = 'Create answer';
- return gSecondConnection.createAnswer();
- })
- .then(function(answer) {
- atStep = 'Set local description at second';
- return gSecondConnection.setLocalDescription(answer);
- })
- .then(function() {
- atStep = 'Set remote description at first';
- return gFirstConnection.setRemoteDescription(
- gSecondConnection.localDescription);
- })
- .catch(test.step_func(function(e) {
- assert_unreached('Error ' + e.name + ': ' + e.message +
- ' happened at step ' + atStep);
- }));
- });
-
- function showStats() {
- // Show the retrieved stats info
- var showStats = document.getElementById('stats');
- showStats.innerHTML = statsToShow;
- }
-
-</script>
-
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<title>Historical WebRTC features</title>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<div id="log"></div>
-<script>
-[
- //'reliable',
- 'maxRetransmitTime',
-].forEach((member) => {
- test(() => {
- assert_false(member in RTCDataChannel.prototype);
- }, `RTCDataChannel member ${member} should not exist`);
-});
-
-[
- //"addStream",
- //"createDTMFSender",
- //"getLocalStreams",
- //"getRemoteStreams",
- "getStreamById",
- //"onaddstream",
- //"onremovestream",
- //"removeStream",
- "updateIce",
-].forEach(function(name) {
- test(function() {
- assert_false(name in RTCPeerConnection.prototype);
- }, "RTCPeerConnection member " + name + " should not exist");
-});
-
-[
- "setDirection",
-].forEach(function(name) {
- test(function() {
- assert_false(name in RTCRtpTransceiver.prototype);
- }, "RTCRtpTransceiver member " + name + " should not exist");
-});
-
-[
- "DataChannel",
- "mozRTCIceCandidate",
- "mozRTCPeerConnection",
- "mozRTCSessionDescription",
- //"webkitRTCPeerConnection",
-].forEach(function(name) {
- test(function() {
- assert_false(name in window);
- }, name + " interface should not exist");
-});
-</script>
+++ /dev/null
-This directory contains files that test for behavior relevant to webrtc,
-particularly defined in https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection legacy addStream</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../support/RTCStats-helper.js"></script>
-<script src="../support/dictionary-helper.js"></script>
-<script>
- 'use strict';
-
- // The following helper functions are called from RTCPeerConnection-helper.js:
- // getUserMediaTracksAndStreams
-
- // The following helper functions are called from RTCStats-helper.js
- // (depends on dictionary-helper.js):
- // validateRtcStats
-
- // TODO(hbos): addStream() is legacy API not in the spec. Based on discussion
- // whether to standardize in legacy section, consider removing this test or
- // keeping it until addTrack() has wide support.
- // https://github.com/w3c/webrtc-pc/issues/1705
- // https://github.com/w3c/webrtc-pc/issues/1125
- async_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- let track;
- let stream;
- getUserMediaTracksAndStreams(1)
- .then(t.step_func(([tracks, streams]) => {
- track = tracks[0];
- stream = streams[0];
- stream.addTrack(track);
- pc.addStream(stream);
- return pc.createOffer();
- }))
- .then(t.step_func(offer => {
- return pc.setLocalDescription(offer);
- }))
- .then(t.step_func(() => {
- return pc.getStats();
- }))
- .then(t.step_func(report => {
- let trackStats = findStatsByTypeAndId(report, 'track', track.id);
- let streamStats = findStatsByTypeAndId(report, 'stream', stream.id);
- assert_true(trackStats != null && streamStats != null,
- 'Has stats for track and stream');
- assert_array_equals(streamStats.trackIds, [ trackStats.id ],
- 'streamStats.trackIds == [ trackStats.id ]');
- validateRtcStats(report, trackStats);
- validateRtcStats(report, streamStats);
- t.done();
- }))
- .catch(t.step_func(reason => {
- assert_unreached(reason);
- }));
- }, 'Legacy addStream(): Media stream stats references track stats');
-
- function findStatsByTypeAndId(report, type, identifier) {
- return findStats(report, stats => {
- return stats.type == type && stats[type + 'Identifier'] == identifier;
- });
- }
-
- function findStats(report, findFunc) {
- for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
- if (findFunc(n.value))
- return n.value;
- }
- return null;
- }
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>Test legacy offerToReceiveAudio/Video options</title>
-<link rel="help" href="https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions">
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- /*
- * 4.3.3.2 Configuration data extensions
- * partial dictionary RTCOfferOptions
- */
-
- /*
- * offerToReceiveAudio of type boolean
- * When this is given a non-false value, no outgoing track of type
- * "audio" is attached to the PeerConnection, and the existing
- * localDescription (if any) doesn't contain any sendrecv or recv
- * audio media sections, createOffer() will behave as if
- * addTransceiver("audio") had been called once prior to the createOffer() call.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer({ offerToReceiveAudio: true })
- .then(offer1 => {
- assert_equals(countAudioLine(offer1.sdp), 1,
- 'Expect created offer to have audio line');
-
- // The first createOffer implicitly calls addTransceiver('audio'),
- // so all following offers will also have audio media section
- // in their SDP.
- return pc.createOffer({ offerToReceiveAudio: false })
- .then(offer2 => {
- assert_equals(countAudioLine(offer2.sdp), 1,
- 'Expect audio line to remain in created offer');
- })
- });
- }, 'createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers');
-
- /*
- * offerToReceiveVideo of type boolean
- * When this is given a non-false value, and no outgoing track
- * of type "video" is attached to the PeerConnection, and the
- * existing localDescription (if any) doesn't contain any sendecv
- * or recv video media sections, createOffer() will behave as if
- * addTransceiver("video") had been called prior to the createOffer() call.
- */
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer({ offerToReceiveVideo: true })
- .then(offer1 => {
- assert_equals(countVideoLine(offer1.sdp), 1,
- 'Expect created offer to have video line');
-
- return pc.createOffer({ offerToReceiveVideo: false })
- .then(offer2 => {
- assert_equals(countVideoLine(offer2.sdp), 1,
- 'Expect video line to remain in created offer');
- })
- });
- }, 'createOffer() with offerToReceiveVideo should add video line to all subsequent created offers');
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer({
- offerToReceiveAudio: true,
- offerToReceiveVideo: false
- }).then(offer1 => {
- assert_equals(countAudioLine(offer1.sdp), 1,
- 'Expect audio line to be found in created offer');
-
- assert_equals(countVideoLine(offer1.sdp), 0,
- 'Expect video line to not be found in create offer');
-
- return pc.createOffer({
- offerToReceiveAudio: false,
- offerToReceiveVideo: true
- }).then(offer2 => {
- assert_equals(countAudioLine(offer2.sdp), 1,
- 'Expect audio line to remain in created offer');
-
- assert_equals(countVideoLine(offer2.sdp), 1,
- 'Expect video line to be found in create offer');
- })
- });
- }, 'createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line');
-
-
- // Run some tests for both audio and video kinds
- ['audio', 'video'].forEach((kind) => {
- const capsKind = kind[0].toUpperCase() + kind.slice(1);
-
- const offerToReceiveTrue = {};
- offerToReceiveTrue[`offerToReceive${capsKind}`] = true;
-
- const offerToReceiveFalse = {};
- offerToReceiveFalse[`offerToReceive${capsKind}`] = false;
-
- // Start testing
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const dummy = pc.createDataChannel('foo'); // Just to have something to offer
-
- return pc.createOffer(offerToReceiveFalse)
- .then(() => {
- assert_equals(pc.getTransceivers().length, 0,
- 'Expect pc to have no transceivers');
- });
- }, `createOffer() with offerToReceive${capsKind} set to false should not create a transceiver`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer(offerToReceiveTrue)
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'recvonly',
- 'Expect transceiver to have "recvonly" direction');
- });
- }, `createOffer() with offerToReceive${capsKind} should create a "recvonly" transceiver`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer(offerToReceiveTrue)
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'recvonly',
- 'Expect transceiver to have "recvonly" direction');
- })
- .then(() => pc.createOffer(offerToReceiveTrue))
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to still have only one transceiver');
- })
- ;
- }, `offerToReceive${capsKind} option should be ignored if a non-stopped "recvonly" transceiver exists`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return getTrackFromUserMedia(kind)
- .then(([track, stream]) => {
- pc.addTrack(track, stream);
- return pc.createOffer();
- })
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'sendrecv',
- 'Expect transceiver to have "sendrecv" direction');
- })
- .then(() => pc.createOffer(offerToReceiveTrue))
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to still have only one transceiver');
- })
- ;
- }, `offerToReceive${capsKind} option should be ignored if a non-stopped "sendrecv" transceiver exists`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return getTrackFromUserMedia(kind)
- .then(([track, stream]) => {
- pc.addTrack(track, stream);
- return pc.createOffer(offerToReceiveFalse);
- })
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'sendonly',
- 'Expect transceiver to have "sendonly" direction');
- })
- ;
- }, `offerToReceive${capsKind} set to false with a track should create a "sendonly" transceiver`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver(kind, {direction: 'recvonly'});
-
- return pc.createOffer(offerToReceiveFalse)
- .then(() => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'inactive',
- 'Expect transceiver to have "inactive" direction');
- })
- ;
- }, `offerToReceive${capsKind} set to false with a "recvonly" transceiver should change the direction to "inactive"`);
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const pc2 = new RTCPeerConnection();
-
- t.add_cleanup(() => pc2.close());
-
- return getTrackFromUserMedia(kind)
- .then(([track, stream]) => {
- pc.addTrack(track, stream);
- return pc.createOffer();
- })
- .then((offer) => pc.setLocalDescription(offer))
- .then(() => pc2.setRemoteDescription(pc.localDescription))
- .then(() => pc2.createAnswer())
- .then((answer) => pc2.setLocalDescription(answer))
- .then(() => pc.setRemoteDescription(pc2.localDescription))
- .then(() => pc.createOffer(offerToReceiveFalse))
- .then((offer) => {
- assert_equals(pc.getTransceivers().length, 1,
- 'Expect pc to have one transceiver');
-
- const transceiver = pc.getTransceivers()[0];
- assert_equals(transceiver.direction, 'sendonly',
- 'Expect transceiver to have "sendonly" direction');
- })
- ;
- }, `subsequent offerToReceive${capsKind} set to false with a track should change the direction to "sendonly"`);
- });
-
- promise_test(t => {
- const pc = new RTCPeerConnection();
-
- t.add_cleanup(() => pc.close());
-
- return pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true })
- .then(() => {
- assert_equals(pc.getTransceivers().length, 2,
- 'Expect pc to have two transceivers');
-
- assert_equals(pc.getTransceivers()[0].direction, 'recvonly',
- 'Expect first transceiver to have "recvonly" direction');
- assert_equals(pc.getTransceivers()[1].direction, 'recvonly',
- 'Expect second transceiver to have "recvonly" direction');
- });
- }, 'offerToReceiveAudio and Video should create two "recvonly" transceivers');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCRtpTransceiver with OfferToReceive legacy options</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- const stopTracks = (...streams) => {
- streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
- };
-
- // comparable() - produces copy of object that is JSON comparable.
- // o = original object (required)
- // t = template of what to examine. Useful if o is non-enumerable (optional)
-
- const comparable = (o, t = o) => {
- if (typeof o != 'object' || !o) {
- return o;
- }
- if (Array.isArray(t) && Array.isArray(o)) {
- return o.map((n, i) => comparable(n, t[i]));
- }
- return Object.keys(t).sort()
- .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
- };
-
- const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
-
- const hasProps = (observed, expected) => {
- const observable = comparable(observed, expected);
- assert_equals(stripKeyQuotes(JSON.stringify(observable)),
- stripKeyQuotes(JSON.stringify(comparable(expected))));
- };
-
- const checkAddTransceiverWithStream = async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- await setMediaPermission();
- const audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
- const videoStream = await navigator.mediaDevices.getUserMedia({video: true});
- t.add_cleanup(() => stopTracks(audioStream, videoStream));
-
- const audio = audioStream.getAudioTracks()[0];
- const video = videoStream.getVideoTracks()[0];
-
- pc.addTransceiver(audio, {streams: [audioStream]});
- pc.addTransceiver(video, {streams: [videoStream]});
-
- hasProps(pc.getTransceivers(),
- [
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: audio},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- stopped: false
- },
- {
- receiver: {track: {kind: "video"}},
- sender: {track: video},
- direction: "sendrecv",
- mid: null,
- currentDirection: null,
- stopped: false
- }
- ]);
-
- const offer = await pc.createOffer();
- assert_true(offer.sdp.includes("a=msid:" + audioStream.id),
- "offer contains the expected audio msid");
- assert_true(offer.sdp.includes("a=msid:" + videoStream.id),
- "offer contains the expected video msid");
- };
-
- const checkAddTransceiverWithOfferToReceive = async (t, kinds) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const propsToSet = kinds.map(kind => {
- if (kind == "audio") {
- return "offerToReceiveAudio";
- } else if (kind == "video") {
- return "offerToReceiveVideo";
- }
- });
-
- const options = {};
-
- for (const prop of propsToSet) {
- options[prop] = true;
- }
-
- let offer = await pc.createOffer(options);
-
- const expected = [];
-
- if (options.offerToReceiveAudio) {
- expected.push(
- {
- receiver: {track: {kind: "audio"}},
- sender: {track: null},
- direction: "recvonly",
- mid: null,
- currentDirection: null,
- stopped: false
- });
- }
-
- if (options.offerToReceiveVideo) {
- expected.push(
- {
- receiver: {track: {kind: "video"}},
- sender: {track: null},
- direction: "recvonly",
- mid: null,
- currentDirection: null,
- stopped: false
- });
- }
-
- hasProps(pc.getTransceivers(), expected);
-
- // Test offerToReceive: false
- for (const prop of propsToSet) {
- options[prop] = false;
- }
-
- // Check that sendrecv goes to sendonly
- for (const transceiver of pc.getTransceivers()) {
- transceiver.direction = "sendrecv";
- }
-
- for (const transceiverCheck of expected) {
- transceiverCheck.direction = "sendonly";
- }
-
- offer = await pc.createOffer(options);
- hasProps(pc.getTransceivers(), expected);
-
- // Check that recvonly goes to inactive
- for (const transceiver of pc.getTransceivers()) {
- transceiver.direction = "recvonly";
- }
-
- for (const transceiverCheck of expected) {
- transceiverCheck.direction = "inactive";
- }
-
- offer = await pc.createOffer(options);
- hasProps(pc.getTransceivers(), expected);
- };
-
-const tests = [
- checkAddTransceiverWithStream,
- function checkAddTransceiverWithOfferToReceiveAudio(t) {
- return checkAddTransceiverWithOfferToReceive(t, ["audio"]);
- },
- function checkAddTransceiverWithOfferToReceiveVideo(t) {
- return checkAddTransceiverWithOfferToReceive(t, ["video"]);
- },
- function checkAddTransceiverWithOfferToReceiveBoth(t) {
- return checkAddTransceiverWithOfferToReceive(t, ["audio", "video"]);
- }
-].forEach(test => promise_test(test, test.name));
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>onaddstream tests</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
- 'use strict';
-
- const stopTracks = (...streams) => {
- streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
- };
-
- const collectEvents = (target, name, check) => {
- const events = [];
- const handler = e => {
- check(e);
- events.push(e);
- };
-
- target.addEventListener(name, handler);
-
- const finishCollecting = () => {
- target.removeEventListener(name, handler);
- return events;
- };
-
- return {finish: finishCollecting};
- };
-
- const collectAddTrackEvents = stream => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(stream.getTracks().includes(e.track),
- "track in addtrack event is in the stream");
- };
- return collectEvents(stream, "addtrack", checkEvent);
- };
-
- const collectRemoveTrackEvents = stream => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(!stream.getTracks().includes(e.track),
- "track in removetrack event is not in the stream");
- };
- return collectEvents(stream, "removetrack", checkEvent);
- };
-
- const collectTrackEvents = pc => {
- const checkEvent = e => {
- assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
- assert_true(e.receiver instanceof RTCRtpReceiver, "Receiver is set on event");
- assert_true(e.transceiver instanceof RTCRtpTransceiver, "Transceiver is set on event");
- assert_true(Array.isArray(e.streams), "Streams is set on event");
- e.streams.forEach(stream => {
- assert_true(stream.getTracks().includes(e.track),
- "Each stream in event contains the track");
- });
- assert_equals(e.receiver, e.transceiver.receiver,
- "Receiver belongs to transceiver");
- assert_equals(e.track, e.receiver.track,
- "Track belongs to receiver");
- };
-
- return collectEvents(pc, "track", checkEvent);
- };
-
- // comparable() - produces copy of object that is JSON comparable.
- // o = original object (required)
- // t = template of what to examine. Useful if o is non-enumerable (optional)
-
- const comparable = (o, t = o) => {
- if (typeof o != 'object' || !o) {
- return o;
- }
- if (Array.isArray(t) && Array.isArray(o)) {
- return o.map((n, i) => comparable(n, t[i]));
- }
- return Object.keys(t).sort()
- .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
- };
-
- const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
-
- const hasProps = (observed, expected) => {
- const observable = comparable(observed, expected);
- assert_equals(stripKeyQuotes(JSON.stringify(observable)),
- stripKeyQuotes(JSON.stringify(comparable(expected))));
- };
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- await setMediaPermission();
- const stream1 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream1));
- const audio1 = stream1.getAudioTracks()[0];
- pc1.addTrack(audio1, stream1);
- const video1 = stream1.getVideoTracks()[0];
- pc1.addTrack(video1, stream1);
-
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
- const stream2 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
- t.add_cleanup(() => stopTracks(stream2));
- const audio2 = stream2.getAudioTracks()[0];
- pc2.addTrack(audio2, stream2);
- const video2 = stream2.getVideoTracks()[0];
- pc2.addTrack(video2, stream2);
-
- const offer = await pc1.createOffer();
-
- let trackEventCollector = collectTrackEvents(pc2);
- let addstreamEventCollector = collectEvents(pc2, "addstream", e => {
- hasProps(e, {stream: {id: stream1.id}});
- assert_equals(e.stream.getAudioTracks().length, 1, "One audio track");
- assert_equals(e.stream.getVideoTracks().length, 1, "One video track");
- });
-
- await pc2.setRemoteDescription(offer);
-
- let addstreamEvents = addstreamEventCollector.finish();
- assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event");
-
- let trackEvents = trackEventCollector.finish();
-
- hasProps(trackEvents,
- [
- {streams: [addstreamEvents[0].stream]},
- {streams: [addstreamEvents[0].stream]}
- ]);
-
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
-
- trackEventCollector = collectTrackEvents(pc1);
- addstreamEventCollector = collectEvents(pc1, "addstream", e => {
- hasProps(e, {stream: {id: stream2.id}});
- assert_equals(e.stream.getAudioTracks().length, 1, "One audio track");
- assert_equals(e.stream.getVideoTracks().length, 1, "One video track");
- });
-
- await pc1.setRemoteDescription(answer);
- addstreamEvents = addstreamEventCollector.finish();
- assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event");
-
- trackEvents = trackEventCollector.finish();
-
- hasProps(trackEvents,
- [
- {streams: [addstreamEvents[0].stream]},
- {streams: [addstreamEvents[0].stream]}
- ]);
- },"Check onaddstream");
-</script>
+++ /dev/null
-<!doctype html>
-
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection No-Media Connection Test</title>
-</head>
-<body>
- <div id="log"></div>
- <h2>iceConnectionState info</h2>
- <div id="stateinfo">
- </div>
-
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script src="support/RTCPeerConnection-helper.js"></script>
- <script type="text/javascript">
- let gFirstConnection = null;
- let gSecondConnection = null;
-
- function onIceCandidate(otherConnction, event, reject) {
- try {
- otherConnction.addIceCandidate(event.candidate);
- } catch(e) {
- reject(e);
- }
- };
-
- function onIceConnectionStateChange(done, failed) {
- try {
- assert_equals(event.type, 'iceconnectionstatechange');
- assert_not_equals(gFirstConnection.iceConnectionState, "failed",
- "iceConnectionState of first connection");
- assert_not_equals(gSecondConnection.iceConnectionState, "failed",
- "iceConnectionState of second connection");
- const stateinfo = document.getElementById('stateinfo');
- stateinfo.innerHTML = 'First: ' + gFirstConnection.iceConnectionState
- + '<br>Second: ' + gSecondConnection.iceConnectionState;
- // Note: All these combinations are legal states indicating that the
- // call has connected. All browsers should end up in completed/completed,
- // but as of this moment, we've chosen to terminate the test early.
- // TODO: Revise test to ensure completed/completed is reached.
- const allowedStates = [ 'connected', 'completed'];
- if (allowedStates.includes(gFirstConnection.iceConnectionState) &&
- allowedStates.includes(gSecondConnection.iceConnectionState)) {
- done();
- }
- } catch(e) {
- failed(e);
- }
- };
-
- // This function starts the test.
- promise_test((test) => {
- return new Promise(async (resolve, reject) => {
- gFirstConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gFirstConnection.close());
- gFirstConnection.onicecandidate =
- (event) => onIceCandidate(gSecondConnection, event, reject);
- gFirstConnection.oniceconnectionstatechange =
- () => onIceConnectionStateChange(resolve, reject);
-
- gSecondConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gSecondConnection.close());
- gSecondConnection.onicecandidate =
- (event) => onIceCandidate(gFirstConnection, event, reject);
- gSecondConnection.oniceconnectionstatechange =
- () => onIceConnectionStateChange(resolve, reject);
-
- const offer = await generateVideoReceiveOnlyOffer(gFirstConnection);
-
- await gFirstConnection.setLocalDescription(offer);
-
- // This would normally go across the application's signaling solution.
- // In our case, the "signaling" is to call this function.
-
- await gSecondConnection.setRemoteDescription({ type: 'offer',
- sdp: offer.sdp });
-
- const answer = await gSecondConnection.createAnswer();
-
- await gSecondConnection.setLocalDescription(answer);
-
- assert_equals(gSecondConnection.getSenders().length, 1);
- assert_not_equals(gSecondConnection.getSenders()[0], null);
- assert_not_equals(gSecondConnection.getSenders()[0].transport, null);
-
- // Similarly, this would go over the application's signaling solution.
- await gFirstConnection.setRemoteDescription({ type: 'answer',
- sdp: answer.sdp });
-
- // The test is terminated by onIceConnectionStateChange() calling resolve
- // once both connections are connected.
- })
- });
-</script>
-
-</body>
-</html>
\ No newline at end of file
+++ /dev/null
-<!doctype html>
-<!--
-This test uses data only, and thus does not require fake media devices.
--->
-
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection Data-Only Connection Test with Promises</title>
-</head>
-<body>
- <div id="log"></div>
- <h2>iceConnectionState info</h2>
- <div id="stateinfo">
- </div>
-
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script type="text/javascript">
- var test = async_test('Can set up a basic WebRTC call with only data using promises.');
-
- var gFirstConnection = null;
- var gSecondConnection = null;
-
- var onIceCandidateToFirst = test.step_func(function(event) {
- gSecondConnection.addIceCandidate(event.candidate);
- });
-
- var onIceCandidateToSecond = test.step_func(function(event) {
- gFirstConnection.addIceCandidate(event.candidate);
- });
-
- var onIceConnectionStateChange = test.step_func(function(event) {
- assert_equals(event.type, 'iceconnectionstatechange');
- var stateinfo = document.getElementById('stateinfo');
- stateinfo.innerHTML = 'First: ' + gFirstConnection.iceConnectionState
- + '<br>Second: ' + gSecondConnection.iceConnectionState;
- // Note: All these combinations are legal states indicating that the
- // call has connected. All browsers should end up in completed/completed,
- // but as of this moment, we've chosen to terminate the test early.
- // TODO: Revise test to ensure completed/completed is reached.
- if (gFirstConnection.iceConnectionState == 'connected' &&
- gSecondConnection.iceConnectionState == 'connected') {
- test.done()
- }
- if (gFirstConnection.iceConnectionState == 'connected' &&
- gSecondConnection.iceConnectionState == 'completed') {
- test.done()
- }
- if (gFirstConnection.iceConnectionState == 'completed' &&
- gSecondConnection.iceConnectionState == 'connected') {
- test.done()
- }
- if (gFirstConnection.iceConnectionState == 'completed' &&
- gSecondConnection.iceConnectionState == 'completed') {
- test.done()
- }
- });
-
- // This function starts the test.
- test.step(function() {
- gFirstConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gFirstConnection.close());
- gFirstConnection.onicecandidate = onIceCandidateToFirst;
- gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
-
- gSecondConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gSecondConnection.close());
- gSecondConnection.onicecandidate = onIceCandidateToSecond;
- gSecondConnection.oniceconnectionstatechange = onIceConnectionStateChange;
-
- // The createDataChannel is necessary and sufficient to make
- // sure the ICE connection be attempted.
- gFirstConnection.createDataChannel('channel');
-
- var atStep = 'Create offer';
-
- gFirstConnection.createOffer()
- .then(function(offer) {
- atStep = 'Set local description at first';
- return gFirstConnection.setLocalDescription(offer);
- })
- .then(function() {
- atStep = 'Set remote description at second';
- return gSecondConnection.setRemoteDescription(
- gFirstConnection.localDescription);
- })
- .then(function() {
- atStep = 'Create answer';
- return gSecondConnection.createAnswer();
- })
- .then(function(answer) {
- atStep = 'Set local description at second';
- return gSecondConnection.setLocalDescription(answer);
- })
- .then(function() {
- atStep = 'Set remote description at first';
- return gFirstConnection.setRemoteDescription(
- gSecondConnection.localDescription);
- })
- .then(function() {
- atStep = 'Negotiation completed';
- })
- .catch(test.step_func(function(e) {
- assert_unreached('Error ' + e.name + ': ' + e.message +
- ' happened at step ' + atStep);
- }));
- });
-</script>
-
-</body>
-</html>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>RTCPeerConnection RTP payload types</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-</head>
-<body>
-<script>
-
-// Test that when creating an offer we do not run out of valid payload types.
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
-
- pc1.addTransceiver('audio', { direction: 'recvonly' });
- pc1.addTransceiver('video', { direction: 'recvonly' });
- const offer = await pc1.createOffer();
-
- // Extract all payload types from the m= lines.
- const payloadTypes = offer.sdp.split('\n')
- .map(line => line.trim())
- .filter(line => line.startsWith('m='))
- .map(line => line.split(' ').slice(3).join(' '))
- .join(' ')
- .split(' ')
- .map(payloadType => parseInt(payloadType, 10));
-
- // The list of allowed payload types is taken from here
- // https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1.
- const forbiddenPayloadTypes = payloadTypes
- .filter(payloadType => {
- if (payloadType >= 96 && payloadType <= 127) {
- return false;
- }
- if (payloadType >= 72 && payloadType < 96) {
- return true;
- }
- if (payloadType >= 35 && payloadType < 72) {
- return false;
- }
- // TODO: Check against static payload type list.
- return false;
- });
- assert_equals(forbiddenPayloadTypes.length, 0)
-}, 'createOffer with the maximum set of codecs does not generate invalid payload types');
-</script>
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection BUNDLE</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => caller.addTrack(track, stream));
-
- let metadataToBeLoaded;
- callee.ontrack = (e) => {
- const stream = e.streams[0];
- const v = document.createElement('video');
- v.autoplay = true;
- v.srcObject = stream;
- v.id = stream.id
- metadataToBeLoaded = new Promise((resolve) => {
- v.addEventListener('loadedmetadata', () => {
- resolve();
- });
- });
- };
- exchangeIceCandidates(caller, callee);
- const offer = await caller.createOffer();
- // remove the a=group:BUNDLE from the SDP when signaling.
- const sdp = offer.sdp.replace(/a=group:BUNDLE (.*)\r\n/, '');
- await callee.setRemoteDescription({type: 'offer', sdp});
- await caller.setLocalDescription(offer);
-
- const answer = await callee.createAnswer();
- await caller.setRemoteDescription(answer);
- await callee.setLocalDescription(answer);
-
- await metadataToBeLoaded;
- const senders = caller.getSenders();
- const dtlsTransports = senders.map(s => s.transport);
- assert_equals(dtlsTransports.length, 2);
- assert_not_equals(dtlsTransports[0], dtlsTransports[1]);
-
- const iceTransports = dtlsTransports.map(t => t.iceTransport);
- assert_equals(iceTransports.length, 2);
- assert_not_equals(iceTransports[0], iceTransports[1]);
-}, 'not negotiating BUNDLE creates two separate ice and dtls transports');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => caller.addTrack(track, stream));
-
- let metadataToBeLoaded;
- callee.ontrack = (e) => {
- const stream = e.streams[0];
- const v = document.createElement('video');
- v.autoplay = true;
- v.srcObject = stream;
- v.id = stream.id
- metadataToBeLoaded = new Promise((resolve) => {
- v.addEventListener('loadedmetadata', () => {
- resolve();
- });
- });
- };
- exchangeIceCandidates(caller, callee);
- const offer = await caller.createOffer();
- await callee.setRemoteDescription(offer);
- await caller.setLocalDescription(offer);
- const secondTransport = caller.getSenders()[1].transport; // Save a reference to this transport.
-
- const answer = await callee.createAnswer();
- await caller.setRemoteDescription(answer);
- await callee.setLocalDescription(answer);
-
- await metadataToBeLoaded;
- const senders = caller.getSenders();
- const dtlsTransports = senders.map(s => s.transport);
- assert_equals(dtlsTransports.length, 2);
- assert_equals(dtlsTransports[0], dtlsTransports[1]);
- assert_not_equals(dtlsTransports[1], secondTransport);
- assert_equals(secondTransport.state, 'closed');
-}, 'bundles on the first transport and closes the second');
-
-</script>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>Candidate exchange</title>
-<meta name=timeout content=long>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-</head>
-<body>
-<script>
-
-class StateLogger {
- constructor(source, eventname, field) {
- source.addEventListener(eventname, event => {
- this.events.push(source[field]);
- });
- this.events = [source[field]];
- }
-}
-
-class IceStateLogger extends StateLogger {
- constructor(source) {
- super(source, 'iceconnectionstatechange', 'iceConnectionState');
- }
-}
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('datachannel');
- pc1IceStates = new IceStateLogger(pc1);
- pc2IceStates = new IceStateLogger(pc1);
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- // Note - it's been claimed that this state sometimes jumps straight
- // to "completed". If so, this test should be flaky.
- await waitForIceStateChange(pc1, ['connected']);
- assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
- assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
-}, 'Two way ICE exchange works');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1IceStates = new IceStateLogger(pc1);
- pc2IceStates = new IceStateLogger(pc1);
- let candidates = [];
- pc1.createDataChannel('datachannel');
- pc1.onicecandidate = e => {
- candidates.push(e.candidate);
- }
- // Candidates from PC2 are not delivered to pc1, so pc1 will use
- // peer-reflexive candidates.
- await exchangeOfferAnswer(pc1, pc2);
- const waiter = waitForIceGatheringState(pc1, ['complete']);
- await waiter;
- for (const candidate of candidates) {
- if (candidate) {
- pc2.addIceCandidate(candidate);
- }
- }
- await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
- waitForIceStateChange(pc2, ['connected', 'completed'])]);
- const candidate_pair = pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
- assert_equals(candidate_pair.local.type, 'host');
- assert_equals(candidate_pair.remote.type, 'prflx');
- assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
- assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
-}, 'Adding only caller -> callee candidates gives a connection');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1IceStates = new IceStateLogger(pc1);
- pc2IceStates = new IceStateLogger(pc1);
- let candidates = [];
- pc1.createDataChannel('datachannel');
- pc2.onicecandidate = e => {
- candidates.push(e.candidate);
- }
- // Candidates from pc1 are not delivered to pc2. so pc2 will use
- // peer-reflexive candidates.
- await exchangeOfferAnswer(pc1, pc2);
- const waiter = waitForIceGatheringState(pc2, ['complete']);
- await waiter;
- for (const candidate of candidates) {
- if (candidate) {
- pc1.addIceCandidate(candidate);
- }
- }
- await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
- waitForIceStateChange(pc2, ['connected', 'completed'])]);
- const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
- assert_equals(candidate_pair.local.type, 'host');
- assert_equals(candidate_pair.remote.type, 'prflx');
- assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
- assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
-}, 'Adding only callee -> caller candidates gives a connection');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1IceStates = new IceStateLogger(pc1);
- pc2IceStates = new IceStateLogger(pc1);
- let pc2ToPc1Candidates = [];
- pc1.createDataChannel('datachannel');
- pc2.onicecandidate = e => {
- pc2ToPc1Candidates.push(e.candidate);
- // This particular test verifies that candidates work
- // properly if added from the pc2 onicecandidate event.
- if (!e.candidate) {
- for (const candidate of pc2ToPc1Candidates) {
- if (candidate) {
- pc1.addIceCandidate(candidate);
- }
- }
- }
- }
- // Candidates from |pc1| are not delivered to |pc2|. |pc2| will use
- // peer-reflexive candidates.
- await exchangeOfferAnswer(pc1, pc2);
- await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
- waitForIceStateChange(pc2, ['connected', 'completed'])]);
- const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
- assert_equals(candidate_pair.local.type, 'host');
- assert_equals(candidate_pair.remote.type, 'prflx');
- assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
- assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
-}, 'Adding callee -> caller candidates from end-of-candidates gives a connection');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1IceStates = new IceStateLogger(pc1);
- pc2IceStates = new IceStateLogger(pc1);
- let pc1ToPc2Candidates = [];
- let pc2ToPc1Candidates = [];
- pc1.createDataChannel('datachannel');
- pc1.onicecandidate = e => {
- pc1ToPc2Candidates.push(e.candidate);
- }
- pc2.onicecandidate = e => {
- pc2ToPc1Candidates.push(e.candidate);
- }
- const offer = await pc1.createOffer();
- await Promise.all([pc1.setLocalDescription(offer),
- pc2.setRemoteDescription(offer)]);
- const answer = await pc2.createAnswer();
- await waitForIceGatheringState(pc1, ['complete']);
- await pc2.setLocalDescription(answer).then(() => {
- for (const candidate of pc1ToPc2Candidates) {
- if (candidate) {
- pc2.addIceCandidate(candidate);
- }
- }
- });
- await waitForIceGatheringState(pc2, ['complete']);
- pc1.setRemoteDescription(answer).then(async () => {
- for (const candidate of pc2ToPc1Candidates) {
- if (candidate) {
- await pc1.addIceCandidate(candidate);
- }
- }
- });
- await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
- waitForIceStateChange(pc2, ['connected', 'completed'])]);
- const candidate_pair =
- pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
- assert_equals(candidate_pair.local.type, 'host');
- // When we supply remote candidates, we expect a jump to the 'host' candidate,
- // but it might also remain as 'prflx'.
- assert_true(candidate_pair.remote.type == 'host' ||
- candidate_pair.remote.type == 'prflx');
- assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
- assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
-}, 'Explicit offer/answer exchange gives a connection');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- pc1.createDataChannel('datachannel');
- pc1.onicecandidate = assert_unreached;
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
- await new Promise(resolve => {
- pc1.onicecandidate = resolve;
- });
-}, 'Candidates always arrive after setLocalDescription(offer) resolves');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('datachannel');
- pc2.onicecandidate = assert_unreached;
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc2.setLocalDescription(await pc2.createAnswer());
- await new Promise(resolve => {
- pc2.onicecandidate = resolve;
- });
-}, 'Candidates always arrive after setLocalDescription(answer) resolves');
-
-</script>
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.createOffer</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../support/RTCStats-helper.js"></script>
-<script>
-'use strict';
-
-// draft-ietf-rtcweb-security-20 section 6.5
-//
-// All Implementations MUST support DTLS 1.2 with the
-// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 cipher suite and the P-256
-// curve [FIPS186].
-// ....... The DTLS-SRTP protection profile
-// SRTP_AES128_CM_HMAC_SHA1_80 MUST be supported for SRTP.
-// Implementations MUST favor cipher suites which support (Perfect
-// Forward Secrecy) PFS over non-PFS cipher suites and SHOULD favor AEAD
-// over non-AEAD cipher suites.
-
-const acceptableTlsVersions = new Set([
- 'FEFD', // DTLS 1.2 - RFC 6437 section 4.1
- '0304', // TLS 1.3 - RFC 8446 section 5.1
-]);
-
-const acceptableDtlsCiphersuites = new Set([
- 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
-]);
-
-const acceptableSrtpCiphersuites = new Set([
- 'SRTP_AES128_CM_HMAC_SHA1_80',
- 'AES_CM_128_HMAC_SHA1_80',
-]);
-
-const acceptableTlsGroups = new Set([
- 'P-256',
-]);
-
-const acceptableValues = {
- 'tlsVersion': acceptableTlsVersions,
- 'dtlsCipher': acceptableDtlsCiphersuites,
- 'srtpCipher': acceptableSrtpCiphersuites,
- //'tlsGroup': acceptableTlsGroups,
-};
-
-function verifyStat(name, transportStats) {
- assert_not_equals(typeof transportStats, 'undefined');
- assert_true(name in transportStats, 'Value present:');
- assert_true(acceptableValues[name].has(transportStats[name]));
-}
-
-for (const name of Object.keys(acceptableValues)) {
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('foo');
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- await waitForState(pc1.sctp.transport, 'connected');
- const statsReport = await pc1.getStats();
- const transportStats = findStatsFromReport(statsReport,
- stats => stats.type === 'transport')
- verifyStat(name, transportStats);
- }, name + ' is acceptable on data-only');
-
- promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- const transceiver = pc1.addTransceiver('video');
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- await waitForState(transceiver.sender.transport, 'connected');
- const statsReport = await pc1.getStats();
- const transportStats = findStatsFromReport(statsReport,
- stats => stats.type === 'transport')
- verifyStat(name, transportStats);
- }, name + ' is acceptable on video-only');
-}
-</script>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>DTLS fingerprint validation</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-</head>
-<body>
-<script>
-
-// Tests that an invalid fingerprint leads to a connectionState 'failed'.
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- pc1.createDataChannel('datachannel');
- exchangeIceCandidates(pc1, pc2);
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription(offer);
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
- await pc1.setRemoteDescription(new RTCSessionDescription({
- type: answer.type,
- sdp: answer.sdp.replace(/a=fingerprint:sha-256 .*/g,
- 'a=fingerprint:sha-256 00:00:00:00:00:00:00:00:00:00:00:00:00:' +
- '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00'),
- }));
- await pc2.setLocalDescription(answer);
-
- await waitForConnectionStateChange(pc1, ['failed']);
- await waitForConnectionStateChange(pc2, ['failed']);
-}, 'Connection fails if one side provides a wrong DTLS fingerprint');
-</script>
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection a=setup SDP parameter test</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-// Tests for correct behavior of DTLS a=setup parameter.
-
-// SDP copied from JSEP Example 7.1
-// It contains two media streams with different ufrags, and bundle
-// turned on.
-const kSdp = `v=0
-o=- 4962303333179871722 1 IN IP4 0.0.0.0
-s=-
-t=0 0
-a=ice-options:trickle
-a=group:BUNDLE a1 v1
-a=group:LS a1 v1
-m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
-c=IN IP4 203.0.113.100
-a=mid:a1
-a=sendrecv
-a=rtpmap:96 opus/48000/2
-a=rtpmap:0 PCMU/8000
-a=rtpmap:8 PCMA/8000
-a=rtpmap:97 telephone-event/8000
-a=rtpmap:98 telephone-event/48000
-a=maxptime:120
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
-a=ice-ufrag:ETEn
-a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10101 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-m=video 10102 UDP/TLS/RTP/SAVPF 100 101
-c=IN IP4 203.0.113.100
-a=mid:v1
-a=sendrecv
-a=rtpmap:100 VP8/90000
-a=rtpmap:101 rtx/90000
-a=fmtp:101 apt=100
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=rtcp-fb:100 ccm fir
-a=rtcp-fb:100 nack
-a=rtcp-fb:100 nack pli
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
-a=ice-ufrag:BGKk
-a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10103 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-`;
-
-for (let setup of ['actpass']) {
- promise_test(async t => {
- const sdp = kSdp.replace(/a=setup:actpass/g,
- 'a=setup:' + setup);
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- await pc1.setRemoteDescription({type: 'offer', sdp: sdp});
- const answer = await pc1.createAnswer();
- const resultingSetup = answer.sdp.match(/a=setup:\S+/);
- if (setup === 'active') {
- assert_equals(resultingSetup[0], 'a=setup:passive');
- } else if (setup === 'passive') {
- assert_equals(resultingSetup[0], 'a=setup:active');
- } else if (setup === 'actpass') {
- // For actpass, either active or passive are legal, although
- // active is RECOMMENDED by RFC 5763 / 8842.
- assert_in_array(resultingSetup[0], ['a=setup:active', 'a=setup:passive']);
- }
- await pc1.setLocalDescription(answer);
- }, 'PC should accept initial offer with setup=' + setup);
-}
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection Handovers</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const offerPc = new RTCPeerConnection();
- const answerPcFirst = new RTCPeerConnection();
- const answerPcSecond = new RTCPeerConnection();
- t.add_cleanup(() => {
- offerPc.close();
- answerPcFirst.close();
- answerPcSecond.close();
- });
- const offerDatachannel1 = offerPc.createDataChannel('initial');
- exchangeIceCandidates(offerPc, answerPcFirst);
-
- // Negotiate connection with PC 1
- const offer1 = await offerPc.createOffer();
- await offerPc.setLocalDescription(offer1);
- await answerPcFirst.setRemoteDescription(offer1);
- const answer1 = await answerPcFirst.createAnswer();
- await offerPc.setRemoteDescription(answer1);
- await answerPcFirst.setLocalDescription(answer1);
- const datachannelAtAnswerPcFirst = await new Promise(
- r => answerPcFirst.ondatachannel = ({channel}) => r(channel));
- const iceTransport = offerPc.sctp.transport;
- // Check that messages get through.
- datachannelAtAnswerPcFirst.send('hello');
- const message1 = await awaitMessage(offerDatachannel1);
- assert_equals(message1, 'hello');
-
- // Renegotiate with PC 2
- // Note - ICE candidates will also be sent to answerPc1, but that shouldn't matter.
- exchangeIceCandidates(offerPc, answerPcSecond);
- const offer2 = await offerPc.createOffer();
- await offerPc.setLocalDescription(offer2);
- await answerPcSecond.setRemoteDescription(offer2);
- const answer2 = await answerPcSecond.createAnswer();
- await offerPc.setRemoteDescription(answer2);
- await answerPcSecond.setLocalDescription(answer2);
-
- // Kill the first PC. This should not affect anything, but leaving it may cause untoward events.
- answerPcFirst.close();
-
- const answerDataChannel2 = answerPcSecond.createDataChannel('second back');
-
- const datachannelAtOfferPcSecond = await new Promise(r => offerPc.ondatachannel = ({channel}) => r(channel));
-
- await new Promise(r => datachannelAtOfferPcSecond.onopen = r);
-
- datachannelAtOfferPcSecond.send('hello again');
- const message2 = await awaitMessage(answerDataChannel2);
- assert_equals(message2, 'hello again');
-}, 'Handover with datachannel reinitiated from new callee completes');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Handovers</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const offerPc = new RTCPeerConnection();
- const answerPcFirst = new RTCPeerConnection();
- const answerPcSecond = new RTCPeerConnection();
- t.add_cleanup(() => {
- offerPc.close();
- answerPcFirst.close();
- answerPcSecond.close();
- });
- offerPc.addTransceiver('audio');
- // Negotiate connection with PC 1
- const offer1 = await offerPc.createOffer();
- await offerPc.setLocalDescription(offer1);
- await answerPcFirst.setRemoteDescription(offer1);
- const answer1 = await answerPcFirst.createAnswer();
- await offerPc.setRemoteDescription(answer1);
- await answerPcFirst.setLocalDescription(answer1);
- // Renegotiate with PC 2
- const offer2 = await offerPc.createOffer();
- await offerPc.setLocalDescription(offer2);
- await answerPcSecond.setRemoteDescription(offer2);
- const answer2 = await answerPcSecond.createAnswer();
- await offerPc.setRemoteDescription(answer2);
- await answerPcSecond.setLocalDescription(answer2);
-}, 'Negotiation of handover initiated at caller works');
-
-promise_test(async t => {
- const offerPc = new RTCPeerConnection();
- const answerPcFirst = new RTCPeerConnection();
- const answerPcSecond = new RTCPeerConnection();
- t.add_cleanup(() => {
- offerPc.close();
- answerPcFirst.close();
- answerPcSecond.close();
- });
- offerPc.addTransceiver('audio');
- // Negotiate connection with PC 1
- const offer1 = await offerPc.createOffer();
- await offerPc.setLocalDescription(offer1);
- await answerPcFirst.setRemoteDescription(offer1);
- const answer1 = await answerPcFirst.createAnswer();
- await offerPc.setRemoteDescription(answer1);
- await answerPcFirst.setLocalDescription(answer1);
- // Renegotiate with PC 2
- // The offer from PC 2 needs to be consistent on at least the following:
- // - Number, type and order of media sections
- // - MID values
- // - Payload type values
- // Do a "fake" offer/answer using the original offer against PC2 to achieve this.
- await answerPcSecond.setRemoteDescription(offer1);
- // Discard the output of this round.
- await answerPcSecond.setLocalDescription(await answerPcSecond.createAnswer());
-
- // Now we can initiate an offer from the new PC.
- const offer2 = await answerPcSecond.createOffer();
- await answerPcSecond.setLocalDescription(offer2);
- await offerPc.setRemoteDescription(offer2);
- const answer2 = await offerPc.createAnswer();
- await answerPcSecond.setRemoteDescription(answer2);
- await offerPc.setLocalDescription(answer2);
-}, 'Negotiation of handover initiated at callee works');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection Failed State</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Tests for correct behavior of ICE state.
-
-// SDP copied from JSEP Example 7.1
-// It contains two media streams with different ufrags, and bundle
-// turned on.
-const kSdp = `v=0
-o=- 4962303333179871722 1 IN IP4 0.0.0.0
-s=-
-t=0 0
-a=ice-options:trickle
-a=group:BUNDLE a1 v1
-a=group:LS a1 v1
-m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
-c=IN IP4 203.0.113.100
-a=mid:a1
-a=sendrecv
-a=rtpmap:96 opus/48000/2
-a=rtpmap:0 PCMU/8000
-a=rtpmap:8 PCMA/8000
-a=rtpmap:97 telephone-event/8000
-a=rtpmap:98 telephone-event/48000
-a=maxptime:120
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
-a=ice-ufrag:ETEn
-a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10101 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-m=video 10102 UDP/TLS/RTP/SAVPF 100 101
-c=IN IP4 203.0.113.100
-a=mid:v1
-a=sendrecv
-a=rtpmap:100 VP8/90000
-a=rtpmap:101 rtx/90000
-a=fmtp:101 apt=100
-a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
-a=rtcp-fb:100 ccm fir
-a=rtcp-fb:100 nack
-a=rtcp-fb:100 nack pli
-a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
-a=ice-ufrag:BGKk
-a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
-a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
-a=setup:actpass
-a=dtls-id:1
-a=rtcp:10103 IN IP4 203.0.113.100
-a=rtcp-mux
-a=rtcp-rsize
-`;
-
-// Returns a promise that resolves when |pc.iceConnectionState| is in one of the
-// wanted states, and rejects if it is in one of the unwanted states.
-// This is a variant of the function in RTCPeerConnection-helper.js.
-function waitForIceStateChange(pc, wantedStates, unwantedStates=[]) {
- return new Promise((resolve, reject) => {
- if (wantedStates.includes(pc.iceConnectionState)) {
- resolve();
- return;
- } else if (unwantedStates.includes(pc.iceConnectionState)) {
- reject('Unexpected state encountered: ' + pc.iceConnectionState);
- return;
- }
- pc.addEventListener('iceconnectionstatechange', () => {
- if (wantedStates.includes(pc.iceConnectionState)) {
- resolve();
- } else if (unwantedStates.includes(pc.iceConnectionState)) {
- reject('Unexpected state encountered: ' + pc.iceConnectionState);
- }
- });
- });
-}
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- let [track, streams] = await getTrackFromUserMedia('video');
- const sender = pc1.addTrack(track);
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- await waitForIceStateChange(pc1, ['connected', 'completed']);
-}, 'PC should enter connected (or completed) state when candidates are sent');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- let [track, streams] = await getTrackFromUserMedia('video');
- const sender = pc1.addTrack(track);
- const offer = await pc1.createOffer();
- assert_greater_than_equal(offer.sdp.search('a=ice-options:trickle'), 0);
-}, 'PC should generate offer with a=ice-options:trickle');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- await pc1.setRemoteDescription({type: 'offer', sdp: kSdp});
- const answer = await pc1.createAnswer();
- await pc1.setLocalDescription(answer);
- assert_greater_than_equal(answer.sdp.search('a=ice-options:trickle'), 0);
- // When we use trickle ICE, and don't signal end-of-caniddates, we
- // expect failure to result in 'disconnected' state rather than 'failed'.
- const stateWaiter = waitForIceStateChange(pc1, ['disconnected'],
- ['failed']);
- // Add a bogus candidate. The candidate is drawn from the
- // IANA "test-net-3" pool (RFC5737), so is guaranteed not to respond.
- const candidateStr1 =
- 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
- await pc1.addIceCandidate({candidate: candidateStr1,
- sdpMid: 'a1',
- usernameFragment: 'ETEn'});
- await stateWaiter;
-}, 'PC should enter disconnected state when a failing candidate is sent');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection Failed State</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-// Tests for validating ice-ufrag and ice-pwd syntax defined in
-// https://tools.ietf.org/html/rfc5245#section-15.4
-// Alphanumeric, '+' and '/' are allowed.
-
-const preamble = `v=0
-o=- 0 3 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
-m=video 1 RTP/SAVPF 100
-c=IN IP4 0.0.0.0
-a=rtcp-mux
-a=sendonly
-a=mid:video
-a=rtpmap:100 VP8/30
-a=setup:actpass
-`;
-const valid_ufrag = 'a=ice-ufrag:ETEn\r\n';
-const valid_pwd = 'a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n';
-const not_ice_char = '$'; // A snowman emoji would be cool but is not interoperable.
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const sdp = preamble +
- valid_ufrag.replace('ETEn', 'E' + not_ice_char + 'En') +
- valid_pwd;
-
- return promise_rejects_dom(t, 'InvalidAccessError',
- pc.setRemoteDescription({type: 'offer', sdp}));
-}, 'setRemoteDescription with a ice-ufrag containing a non-ice-char fails');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- const sdp = preamble +
- valid_ufrag +
- valid_pwd.replace('K0Wp', 'K' + not_ice_char + 'Wp');
-
- return promise_rejects_dom(t, 'InvalidAccessError',
- pc.setRemoteDescription({type: 'offer', sdp}));
-}, 'setRemoteDescription with a ice-pwd containing a non-ice-char fails');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.createOffer</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
- 'use strict';
-
- // Tests for the construction of initial offers according to
- // draft-ietf-rtcweb-jsep-24 section 5.2.1
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const offer = await generateVideoReceiveOnlyOffer(pc);
- let offer_lines = offer.sdp.split('\r\n');
- // The first 3 lines are dictated by JSEP.
- assert_equals(offer_lines[0], "v=0");
- assert_equals(offer_lines[1].slice(0, 2), "o=");
-
- assert_regexp_match(offer_lines[1], /^o=\S+ \d+ \d+ IN IP4 \S+$/);
- const fields = RegExp(/^o=\S+ (\d+) (\d+) IN IP4 (\S+)/).exec(offer_lines[1]);
- // Per RFC 3264, the sess-id should be representable in an uint64
- // Note: JSEP -24 has this wrong - see bug:
- // https://github.com/rtcweb-wg/jsep/issues/855
- assert_less_than(Number(fields[1]), 2**64);
- // Per RFC 3264, the version should be less than 2^62 to avoid overflow
- assert_less_than(Number(fields[2]), 2**62);
- // JSEP says that the address part SHOULD be a meaningless address
- // "such as" IN IP4 0.0.0.0. This is to prevent unintentional disclosure
- // of IP addresses, so this is important enough to verify. Right now we
- // allow 127.0.0.1 and 0.0.0.0, but there are other things we could allow.
- // Maybe 0.0.0.0/8, 127.0.0.0/8, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24?
- // (See RFC 3330, RFC 5737)
- assert_true(fields[3] == "0.0.0.0" || fields[3] == "127.0.0.1",
- fields[3] + " must be a meaningless IPV4 address")
-
- assert_regexp_match(offer_lines[2], /^s=\S+$/);
- // After this, the order is not dictated by JSEP.
- // TODO: Check lines subsequent to the s= line.
- }, 'Offer conforms to basic SDP requirements');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerconnection SDP parse tests</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-function removeSdpLines(description, toRemove) {
- const edited = description.sdp.split('\n').filter(function(line) {
- return (!line.startsWith(toRemove));
- }).join('\n');
- return {type: description.type, sdp: edited};
-}
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- t.add_cleanup(() => callee.close());
- caller.addTrack(trackFactories.audio());
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- let remote_offer = removeSdpLines(offer, 'a=mid:');
- remote_offer = removeSdpLines(remote_offer, 'a=group:');
- await callee.setRemoteDescription(remote_offer);
- const answer = await callee.createAnswer();
- await caller.setRemoteDescription(answer);
-}, 'Offer description with no mid is accepted');
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- t.add_cleanup(() => callee.close());
- caller.addTrack(trackFactories.audio());
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- let remote_answer = removeSdpLines(answer, 'a=mid:');
- remote_answer = removeSdpLines(remote_answer, 'a=group:');
- await caller.setRemoteDescription(remote_answer);
-}, 'Answer description with no mid is accepted');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerconnection MSID parsing</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-const preamble = `v=0
-o=- 0 3 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
-a=ice-ufrag:6HHHdzzeIhkE0CKj
-a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew
-m=video 1 RTP/SAVPF 100
-c=IN IP4 0.0.0.0
-a=rtcp-mux
-a=sendonly
-a=mid:video
-a=rtpmap:100 VP8/30
-a=setup:actpass
-`;
-
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const ontrackPromise = addEventListenerPromise(t, pc, 'track');
- await pc.setRemoteDescription({type: 'offer', sdp: preamble});
- const trackevent = await ontrackPromise;
- assert_equals(pc.getReceivers().length, 1);
- assert_equals(trackevent.streams.length, 1, 'Stream count');
-}, 'Description with no msid produces a track with a stream');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const ontrackPromise = addEventListenerPromise(t, pc, 'track');
- await pc.setRemoteDescription({type: 'offer',
- sdp: preamble + 'a=msid:- foobar\n'});
- const trackevent = await ontrackPromise;
- assert_equals(pc.getReceivers().length, 1);
- assert_equals(trackevent.streams.length, 0);
-}, 'Description with msid:- appid produces a track with no stream');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const ontrackPromise = addEventListenerPromise(t, pc, 'track');
- await pc.setRemoteDescription({type: 'offer',
- sdp: preamble + 'a=msid:foo bar\n'});
- const trackevent = await ontrackPromise;
- assert_equals(pc.getReceivers().length, 1);
- assert_equals(trackevent.streams.length, 1);
- assert_equals(trackevent.streams[0].id, 'foo');
-}, 'Description with msid:foo bar produces a stream with id foo');
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const ontrackPromise = addEventListenerPromise(t, pc, 'track');
- await pc.setRemoteDescription({type: 'offer',
- sdp: preamble + 'a=msid:foo bar\n'
- + 'a=msid:baz bar\n'});
- const trackevent = await ontrackPromise;
- assert_equals(pc.getReceivers().length, 1);
- assert_equals(trackevent.streams.length, 2);
-}, 'Description with two msid produces two streams');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<!-- This file contains a test that waits for two seconds. -->
-<meta name="timeout" content="long">
-<title>RTP clockrate</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-async function initiateSingleTrackCallAndReturnReceiver(t, kind) {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({[kind]:true});
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
- pc1.addTrack(track, stream);
-
- exchangeIceCandidates(pc1, pc2);
- const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
- await exchangeAnswer(pc1, pc2);
- await waitForConnectionStateChange(pc2, ['connected']);
- return trackEvent.receiver;
-}
-
-promise_test(async t => {
- // the getSynchronizationSources API exposes the rtp timestamp.
- const receiver = await initiateSingleTrackCallAndReturnReceiver(t, 'video');
- const first = await listenForSSRCs(t, receiver);
- await new Promise(resolve => t.step_timeout(resolve, 2000));
- const second = await listenForSSRCs(t, receiver);
- // rtpTimestamp may wrap at 0xffffffff, take care of that.
- const actualClockRate = ((second[0].rtpTimestamp - first[0].rtpTimestamp + 0xffffffff) % 0xffffffff) / (second[0].timestamp - first[0].timestamp) * 1000;
- assert_approx_equals(actualClockRate, 90000, 9000, 'Video clockrate is approximately 90000');
-}, 'video rtp timestamps increase by approximately 90000 per second');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection payload type demuxing</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const caller = new RTCPeerConnection({bundlePolicy: 'max-compat'});
- t.add_cleanup(() => caller.close());
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- exchangeIceCandidates(caller, callee);
-
- const stream = await getNoiseStream({video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => caller.addTrack(track, stream));
- stream.getTracks().forEach(track => caller.addTrack(track.clone(), stream.clone()));
-
- let callCount = 0;
- let metadataToBeLoaded = new Promise(resolve => {
- callee.ontrack = (e) => {
- const stream = e.streams[0];
- const v = document.createElement('video');
- v.autoplay = true;
- v.srcObject = stream;
- v.id = stream.id
- v.addEventListener('loadedmetadata', () => {
- if (++callCount === 2) {
- resolve();
- }
- });
- };
- });
-
- const offer = await caller.createOffer();
- // Replace BUNDLE, the mid header extension and all ssrc lines
- // with bogus. The receiver will be forced to do payload type demuxing
- // which is still possible because the different m-lines arrive on
- // different ports/sockets.
- const sdp = offer.sdp.replace('BUNDLE', 'SOMETHING')
- .replace(/rtp-hdrext:sdes/g, 'rtp-hdrext:something')
- .replace(/a=ssrc:/g, 'a=notssrc');
-
- await callee.setRemoteDescription({type: 'offer', sdp});
- await caller.setLocalDescription(offer);
-
- const answer = await callee.createAnswer();
- await caller.setRemoteDescription(answer);
- await callee.setLocalDescription(answer);
-
- await metadataToBeLoaded;
-}, 'Can demux two video tracks with the same payload type on an unbundled connection');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>payload type handling (assuming rtcp-mux)</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-// Tests behaviour from https://tools.ietf.org/html/rfc5761#section-4
-
-function createOfferSdp(opusPayloadType) {
- return `v=0
-o=- 0 3 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
-a=ice-ufrag:6HHHdzzeIhkE0CKj
-a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew
-m=audio 9 RTP/SAVPF ${opusPayloadType}
-c=IN IP4 0.0.0.0
-a=rtcp-mux
-a=sendonly
-a=mid:audio
-a=rtpmap:${opusPayloadType} opus/48000/2
-a=setup:actpass
-`;
-}
-
-promise_test(async t => {
- for (let payloadType = 96; payloadType <= 127; payloadType++) {
- const pc = new RTCPeerConnection();
- await pc.setRemoteDescription({type: 'offer', sdp: createOfferSdp(payloadType)});
- const answer = await pc.createAnswer();
- assert_true(answer.sdp.includes(`a=rtpmap:${payloadType} opus/48000/2`));
- pc.close();
- }
-}, 'setRemoteDescription with a codec in the range 96-127 works');
-
-// This is written as a separate test since it currently fails in Chrome.
-promise_test(async t => {
- for (let payloadType = 35; payloadType <= 63; payloadType++) {
- const pc = new RTCPeerConnection();
- await pc.setRemoteDescription({type: 'offer', sdp: createOfferSdp(payloadType)});
- const answer = await pc.createAnswer();
- assert_true(answer.sdp.includes(`a=rtpmap:${payloadType} opus/48000/2`));
- pc.close();
- }
-}, 'setRemoteDescription with a codec in the range 35-63 works');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTX codec integrity checks</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../third_party/sdp/sdp.js"></script>
-<script>
-'use strict';
-
-// Tests for conformance to rules for RTX codecs.
-// Basic rule: Offers and answers must contain RTX codecs, and the
-// RTX codecs must have an a=fmtp line that points to a non-RTX codec.
-
-// Helper function for doing one round of offer/answer exchange
-// between two local peer connections.
-// Calls setRemoteDescription(offer/answer) before
-// setLocalDescription(offer/answer) to ensure the remote description
-// is set and candidates can be added before the local peer connection
-// starts generating candidates and ICE checks.
-async function doSignalingHandshake(localPc, remotePc, options={}) {
- let offer = await localPc.createOffer();
- // Modify offer if callback has been provided
- if (options.modifyOffer) {
- offer = await options.modifyOffer(offer);
- }
-
- // Apply offer.
- await remotePc.setRemoteDescription(offer);
- await localPc.setLocalDescription(offer);
-
- let answer = await remotePc.createAnswer();
- // Modify answer if callback has been provided
- if (options.modifyAnswer) {
- answer = await options.modifyAnswer(answer);
- }
-
- // Apply answer.
- await localPc.setRemoteDescription(answer);
- await remotePc.setLocalDescription(answer);
-}
-
-function verifyRtxReferences(description) {
- const mediaSection = SDPUtils.getMediaSections(description.sdp)[0];
- const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
- for (const codec of rtpParameters.codecs) {
- if (codec.name === 'rtx') {
- assert_own_property(codec.parameters, 'apt', 'rtx codec has apt parameter');
- const referenced_codec = rtpParameters.codecs.find(
- c => c.payloadType === parseInt(codec.parameters.apt));
- assert_true(referenced_codec !== undefined, `Found referenced codec`);
- }
- }
-}
-
-
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- const offer = await generateVideoReceiveOnlyOffer(pc);
- verifyRtxReferences(offer);
-}, 'Initial offer should have sensible RTX mappings');
-
-async function negotiateAndReturnAnswer(t) {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
- let [track, streams] = await getTrackFromUserMedia('video');
- const sender = pc1.addTrack(track);
- await doSignalingHandshake(pc1, pc2);
- return pc2.localDescription;
-}
-
-promise_test(async t => {
- const answer = await negotiateAndReturnAnswer(t);
- verifyRtxReferences(answer);
-}, 'Self-negotiated answer should have sensible RTX parameters');
-
-promise_test(async t => {
- const sampleOffer = `v=0
-o=- 1878890426675213188 2 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=group:BUNDLE video
-a=msid-semantic: WMS
-m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99
-c=IN IP4 0.0.0.0
-a=rtcp:9 IN IP4 0.0.0.0
-a=ice-ufrag:RGPK
-a=ice-pwd:rAyHEAKC7ckxQgWaRZXukz+Z
-a=ice-options:trickle
-a=fingerprint:sha-256 8C:29:0A:8F:11:06:BF:1C:58:B3:CA:E6:F1:F1:DC:99:4C:6C:89:E9:FF:BC:D4:38:11:18:1F:40:19:C8:49:37
-a=setup:actpass
-a=mid:video
-a=recvonly
-a=rtcp-mux
-a=rtpmap:97 rtx/90000
-a=fmtp:97 apt=98
-a=rtpmap:98 VP8/90000
-a=rtcp-fb:98 ccm fir
-a=rtcp-fb:98 nack
-a=rtcp-fb:98 nack pli
-a=rtcp-fb:98 goog-remb
-a=rtcp-fb:98 transport-cc
-`;
- const pc = new RTCPeerConnection();
- let [track, streams] = await getTrackFromUserMedia('video');
- const sender = pc.addTrack(track);
- await pc.setRemoteDescription({type: 'offer', sdp: sampleOffer});
- const answer = await pc.createAnswer();
- verifyRtxReferences(answer);
-}, 'A remote offer generates sensible RTX references in answer');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerconnection SDP SCTP format test</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- t.add_cleanup(() => callee.close());
- caller.createDataChannel('channel');
- const offer = await caller.createOffer();
- const [preamble, media_section, postamble] = offer.sdp.split('\r\nm=');
- assert_true(typeof(postamble) === 'undefined');
- assert_greater_than(media_section.search(
- /^application \d+ UDP\/DTLS\/SCTP webrtc-datachannel\r\n/), -1);
- assert_greater_than(media_section.search(/\r\na=sctp-port:\d+\r\n/), -1);
- assert_greater_than(media_section.search(/\r\na=mid:/), -1);
-}, 'Generated Datachannel SDP uses correct SCTP offer syntax');
-
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<meta name="timeout" content="long">
-<title>RTCPeerConnection MUST NOT support SDES</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../third_party/sdp/sdp.js"></script>
-<script>
-'use strict';
-
-// Test support for
-// https://www.rfc-editor.org/rfc/rfc8826#section-4.3.1
-
-const sdp = `v=0
-o=- 0 3 IN IP4 127.0.0.1
-s=-
-t=0 0
-m=video 9 UDP/TLS/RTP/SAVPF 100
-c=IN IP4 0.0.0.0
-a=rtcp-mux
-a=sendonly
-a=mid:video
-a=rtpmap:100 VP8/90000
-a=fmtp:100 max-fr=30;max-fs=3600
-a=crypto:0 AES_CM_128_HMAC_SHA1_80 inline:2nra27hTUb9ilyn2rEkBEQN9WOFts26F/jvofasw
-a=ice-ufrag:ETEn
-a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l
-`;
-
-// Negative test for Chrome legacy behavior.
-/*
-promise_test(async t => {
- const sdes_constraint = {'mandatory': {'DtlsSrtpKeyAgreement': false}};
- const pc = new RTCPeerConnection(null, sdes_constraint);
- t.add_cleanup(() => pc.close());
-
- pc.addTransceiver('audio');
- const offer = await pc.createOffer();
- assert_false(offer.sdp.includes('\na=crypto:'));
-}, 'does not create offers with SDES');
-*/
-
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
-
- try {
- await pc.setRemoteDescription({type: 'offer', sdp});
- assert_unreached("Must not accept SDP without fingerprint");
- } catch (e) {
- // TODO: which error is correct? See
- // https://github.com/w3c/webrtc-pc/issues/2672
- assert_true(['OperationError', 'InvalidAccessError'].includes(e.name));
- }
-}, 'rejects a remote offer that only includes SDES and no DTLS fingerprint');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Answer</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-// Tests for the construction of answers with simulcast according to:
-// draft-ietf-mmusic-sdp-simulcast-13
-// draft-ietf-mmusic-rid-15
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const expected_rids = ['foo', 'bar', 'baz'];
-
- const offer_sdp = `v=0
-o=- 3840232462471583827 2 IN IP4 127.0.0.1
-s=-
-t=0 0
-a=group:BUNDLE 0
-a=msid-semantic: WMS
-m=video 9 UDP/TLS/RTP/SAVPF 96
-c=IN IP4 0.0.0.0
-a=rtcp:9 IN IP4 0.0.0.0
-a=ice-ufrag:Li6+
-a=ice-pwd:3C05CTZBRQVmGCAq7hVasHlT
-a=ice-options:trickle
-a=fingerprint:sha-256 5B:D3:8E:66:0E:7D:D3:F3:8E:E6:80:28:19:FC:55:AD:58:5D:B9:3D:A8:DE:45:4A:E7:87:02:F8:3C:0B:3B:B3
-a=setup:actpass
-a=mid:0
-a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
-a=recvonly
-a=rtcp-mux
-a=rtpmap:96 VP8/90000
-a=rtcp-fb:96 goog-remb
-a=rtcp-fb:96 transport-cc
-a=rtcp-fb:96 ccm fir
-a=rid:foo recv
-a=rid:bar recv
-a=rid:baz recv
-a=simulcast:recv foo;bar;baz
-`;
-
- await pc.setRemoteDescription({type: 'offer', sdp: offer_sdp});
- const transceiver = pc.getTransceivers()[0];
- // The created transceiver should be in "recvonly" state. Allow it to send.
- transceiver.direction = "sendonly";
- const answer = await pc.createAnswer();
- let answer_lines = answer.sdp.split('\r\n');
- // Check for a RID line for each layer.
- for (const rid of expected_rids) {
- let result = answer_lines.find(line => line.startsWith(`a=rid:${rid}`));
- assert_not_equals(result, undefined, `RID attribute for '${rid}' missing.`);
- }
-
- // Check for simulcast attribute with send direction and all RIDs.
- let result = answer_lines.find(
- line => line.startsWith(`a=simulcast:send ${expected_rids.join(';')}`));
- assert_not_equals(result, undefined, "Could not find simulcast attribute.");
-}, 'createAnswer() with multiple send encodings should create simulcast answer');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Offer</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-// Tests for the construction of offers with simulcast according to:
-// draft-ietf-mmusic-sdp-simulcast-13
-// draft-ietf-mmusic-rid-15
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const expected_rids = ['foo', 'bar', 'baz'];
- pc.addTransceiver('video', {
- sendEncodings: expected_rids.map(rid => ({rid}))
- });
-
- const offer = await pc.createOffer();
- let offer_lines = offer.sdp.split('\r\n');
- // Check for a RID line for each layer.
- for (const rid of expected_rids) {
- let result = offer_lines.find(line => line.startsWith(`a=rid:${rid}`));
- assert_not_equals(result, undefined, `RID attribute for '${rid}' missing.`);
- }
-
- // Check for simulcast attribute with send direction and all RIDs.
- let result = offer_lines.find(
- line => line.startsWith(`a=simulcast:send ${expected_rids.join(';')}`));
- assert_not_equals(result, undefined, "Could not find simulcast attribute.");
-}, 'createOffer() with multiple send encodings should create simulcast offer');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection BUNDLE</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../third_party/sdp/sdp.js"></script>
-<script>
-'use strict';
-promise_test(async t => {
- const caller = new RTCPeerConnection();
- t.add_cleanup(() => caller.close());
- const calleeAudio = new RTCPeerConnection();
- t.add_cleanup(() => calleeAudio.close());
- const calleeVideo = new RTCPeerConnection();
- t.add_cleanup(() => calleeVideo.close());
-
- const stream = await getNoiseStream({audio: true, video: true});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- stream.getTracks().forEach(track => caller.addTrack(track, stream));
-
- let metadataToBeLoaded;
- calleeVideo.ontrack = (e) => {
- const stream = e.streams[0];
- const v = document.createElement('video');
- v.autoplay = true;
- v.srcObject = stream;
- v.id = stream.id
- metadataToBeLoaded = new Promise((resolve) => {
- v.addEventListener('loadedmetadata', () => {
- resolve();
- });
- });
- };
-
- caller.addEventListener('icecandidate', (e) => {
- // route depending on sdpMlineIndex
- if (e.candidate) {
- const target = e.candidate.sdpMLineIndex === 0 ? calleeAudio : calleeVideo;
- target.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
- } else {
- calleeAudio.addIceCandidate();
- calleeVideo.addIceCandidate();
- }
- });
- calleeAudio.addEventListener('icecandidate', (e) => {
- if (e.candidate) {
- caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
- }
- // Note: caller.addIceCandidate is only called for video to avoid calling it twice.
- });
- calleeVideo.addEventListener('icecandidate', (e) => {
- if (e.candidate) {
- caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
- } else {
- caller.addIceCandidate();
- }
- });
-
- const offer = await caller.createOffer();
- const sections = SDPUtils.splitSections(offer.sdp);
- // Remove the a=group:BUNDLE from the SDP when signaling.
- const bundle = SDPUtils.matchPrefix(sections[0], 'a=group:BUNDLE')[0];
- sections[0] = sections[0].replace(bundle + '\r\n', '');
-
- const audioSdp = sections[0] + sections[1];
- const videoSdp = sections[0] + sections[2];
-
- await calleeAudio.setRemoteDescription({type: 'offer', sdp: audioSdp});
- await calleeVideo.setRemoteDescription({type: 'offer', sdp: videoSdp});
- await caller.setLocalDescription(offer);
-
- const answerAudio = await calleeAudio.createAnswer();
- const answerVideo = await calleeVideo.createAnswer();
- const audioSections = SDPUtils.splitSections(answerAudio.sdp);
- const videoSections = SDPUtils.splitSections(answerVideo.sdp);
-
- // Remove the fingerprint from the session part of the SDP if present
- // and move it to the media section.
- SDPUtils.matchPrefix(audioSections[0], 'a=fingerprint:').forEach(line => {
- audioSections[0] = audioSections[0].replace(line + '\r\n', '');
- audioSections[1] += line + '\r\n';
- });
- SDPUtils.matchPrefix(videoSections[0], 'a=fingerprint:').forEach(line => {
- videoSections[0] = videoSections[0].replace(line + '\r\n', '');
- videoSections[1] += line + '\r\n';
- });
-
- const sdp = audioSections[0] + audioSections[1] + videoSections[1];
- await caller.setRemoteDescription({type: 'answer', sdp});
- await calleeAudio.setLocalDescription(answerAudio);
- await calleeVideo.setLocalDescription(answerVideo);
-
- await metadataToBeLoaded;
- assert_equals(calleeAudio.connectionState, 'connected');
- assert_equals(calleeVideo.connectionState, 'connected');
-}, 'Connect audio and video to two independent PeerConnections');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerconnection SDP handling of unknown media types</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- t.add_cleanup(() => pc2.close());
-
- const stream = await getNoiseStream({audio: true});
- pc1.addTrack(stream.getTracks()[0], stream);
- const offer = await pc1.createOffer();
- await pc2.setRemoteDescription({
- type: 'offer',
- sdp: offer.sdp
- .replace('m=audio ', 'm=unicorns ')
- });
- await pc1.setLocalDescription(offer);
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- // Do not attempt to call pc1.setRemoteDescription.
-
- const [preamble, media_section, postamble] = answer.sdp.split('\r\nm=');
- assert_true(typeof(postamble) === 'undefined');
- assert_greater_than(media_section.search(
- /^unicorns 0/), -1);
-}, 'Unknown media types are rejected with the port set to 0');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection.prototype.createOffer</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script>
-'use strict';
-
-/*
- * Chromium note: this requires build bots with H264 support. See
- * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
- * for details on how to enable support.
- */
-// Tests for conformance to RFC 7742,
-// "WebRTC Video Processing and Codec Requirements"
-// The document was formerly known as draft-ietf-rtcweb-video-codecs.
-//
-// This tests that the browser is a WebRTC Browser as defined there.
-
-// TODO: Section 3.2: screen capture video MUST be prepared
-// to handle resolution changes.
-
-// TODO: Section 4: MUST support generating CVO (orientation)
-
-// Section 5: Browsers MUST implement VP8 and H.264 Constrained Baseline
-promise_test(async t => {
- const pc = new RTCPeerConnection();
- const offer = await generateVideoReceiveOnlyOffer(pc);
- let video_section_found = false;
- for (let section of offer.sdp.split(/\r\nm=/)) {
- if (section.search('video') != 0) {
- continue;
- }
- video_section_found = true;
- // RTPMAP lines have the format a=rtpmap:<pt> <codec>/<clock rate>
- let rtpmap_regex = /\r\na=rtpmap:(\d+) (\S+)\/\d+\r\n/g;
- let match = rtpmap_regex.exec(offer.sdp);
- let payload_type_map = new Array();
- while (match) {
- payload_type_map[match[1]] = match[2];
- match = rtpmap_regex.exec(offer.sdp);
- }
- assert_true(payload_type_map.indexOf('VP8') > -1,
- 'VP8 is supported');
- assert_true(payload_type_map.indexOf('H264') > -1,
- 'H.264 is supported');
- // TODO: Verify that one of the H.264 PTs supports constrained baseline
- }
- assert_true(video_section_found);
-}, 'H.264 and VP8 should be supported in initial offer');
-
-async function negotiateParameters() {
- const pc1 = new RTCPeerConnection();
- const pc2 = new RTCPeerConnection();
- let [track, streams] = await getTrackFromUserMedia('video');
- const sender = pc1.addTrack(track);
- await exchangeOfferAnswer(pc1, pc2);
- return sender.getParameters();
-}
-
-function parseFmtp(fmtp) {
- const params = fmtp.split(';');
- return params.map(param => param.split('='));
-}
-promise_test(async t => {
- const params = await negotiateParameters();
- assert_true(!!params.codecs.find(codec => codec.mimeType === 'video/H264'));
- assert_true(!!params.codecs.find(codec => codec.mimeType === 'video/VP8'));
-}, 'H.264 and VP8 should be negotiated after handshake');
-
-// TODO: Section 6: Recipients MUST be able to decode 320x240@20 fps
-// TODO: Section 6.1: VP8 MUST support RFC 7741 payload formats
-// TODO: Section 6.1: VP8 MUST respect max-fr/max-fs
-// TODO: Section 6.1: VP8 MUST encode and decode square pixels
-// TODO: Section 6.2: H.264 MUST support RFC 6184 payload formats
-// TODO: Section 6.2: MUST support Constrained Baseline level 1.2
-// TODO: Section 6.2: SHOULD support Constrained High level 1.3
-// TODO: Section 6.2: MUST support packetization mode 1.
-promise_test(async t => {
- const params = await negotiateParameters();
- const h264 = params.codecs.filter(codec => codec.mimeType === 'video/H264');
- h264.map(codec => {
- const codec_params = parseFmtp(codec.sdpFmtpLine);
- assert_true(!!codec_params.find(x => x[0] === 'profile-level-id'));
- })
-}, 'All H.264 codecs MUST include profile-level-id');
-
-// TODO: Section 6.2: SHOULD interpret max-mbps, max-smbps, max-fs et al
-// TODO: Section 6.2: MUST NOT include sprop-parameter-sets
-// TODO: Section 6.2: MUST support SEI "filler payload"
-// TODO: Section 6.2: MUST support SEI "full frame freeze"
-// TODO: Section 6.2: MUST be prepared to receive User Data messages
-// TODO: Section 6.2: MUST encode and decode square pixels unless signaled
-</script>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
- <meta charset="utf-8">
- <title>Remote tracks should not get ended except for stop/close</title>
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script src="../resources/testdriver.js"></script>
- <script src="../resources/testdriver-vendor.js"></script>
- <script src="support/permission-helper.js"></script>
- <script src="support/RTCPeerConnection-helper.js"></script>
-</head>
-<body>
- <video id="video" controls autoplay playsinline></video>
- <script>
- let pc1, pc2;
- let localTrack, remoteTrack;
- promise_test(async (test) => {
- await setMediaPermission("granted", ["microphone"]);
- const localStream = await navigator.mediaDevices.getUserMedia({audio: true});
- localTrack = localStream.getAudioTracks()[0];
-
- pc1 = new RTCPeerConnection();
- pc1.addTrack(localTrack, localStream);
- pc2 = new RTCPeerConnection();
-
- let trackPromise = new Promise(resolve => {
- pc2.ontrack = e => resolve(e.track);
- });
-
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
-
- remoteTrack = await trackPromise;
- video.srcObject = new MediaStream([remoteTrack]);
- await video.play();
- }, "Setup audio call");
-
- promise_test(async (test) => {
- pc1.getTransceivers()[0].direction = "inactive";
-
- let offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer);
-
- // Let's remove ssrc lines
- let sdpLines = offer.sdp.split("\r\n");
- offer.sdp = sdpLines.filter(line => line && !line.startsWith("a=ssrc")).join("\r\n") + "\r\n";
-
- await pc2.setRemoteDescription(offer);
- let answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription(answer);
-
- assert_equals(remoteTrack.readyState, "live");
- }, "Inactivate the audio transceiver");
-
- promise_test(async (test) => {
- pc1.getTransceivers()[0].direction = "sendonly";
-
- await exchangeOfferAnswer(pc1, pc2);
-
- assert_equals(remoteTrack.readyState, "live");
- }, "Reactivate the audio transceiver");
-
- promise_test(async (test) => {
- pc1.close();
- pc2.close();
- localTrack.stop();
- }, "Clean-up");
- </script>
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<script src="../resources/testharness.js"></script>
-<script src="../resources/testharnessreport.js"></script>
-<script>
-'use strict';
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const audioTransceiver = pc1.addTransceiver('audio', {direction:'recvonly'});
-
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-
- audioTransceiver.direction = 'sendrecv';
-
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-}, '[audio] recvonly transceiver can become sendrecv');
-
-promise_test(async t => {
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- const videoTransceiver = pc1.addTransceiver('video', {direction:'recvonly'});
-
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-
- videoTransceiver.direction = 'sendrecv';
-
- await pc1.setLocalDescription();
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription();
- await pc1.setRemoteDescription(pc2.localDescription);
-}, '[video] recvonly transceiver can become sendrecv');
-
-</script>
+++ /dev/null
-<!doctype html>
-<script>
-window.onmessage = async (event) => {
- let certificate = event.data;
- if (!certificate)
- certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256'});
- event.source.postMessage(certificate, "*");
-}
-</script>
+++ /dev/null
-<!doctype html>
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection Connection Test</title>
- <script src="support/RTCPeerConnection-helper.js"></script>
-</head>
-<body>
- <div id="log"></div>
- <div>
- <video id="local-view" muted autoplay="autoplay"></video>
- <video id="remote-view" muted autoplay="autoplay"/>
- </video>
- </div>
-
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script type="text/javascript">
- var test = async_test('Can set up a basic WebRTC call without announcing ssrcs.');
-
- var gFirstConnection = null;
- var gSecondConnection = null;
-
- // if the remote video gets video data that implies the negotiation
- // as well as the ICE and DTLS connection are up.
- document.getElementById('remote-view')
- .addEventListener('loadedmetadata', function() {
- // Call negotiated: done.
- test.done();
- });
-
- function getNoiseStreamOkCallback(localStream) {
- gFirstConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gFirstConnection.close());
- gFirstConnection.onicecandidate = onIceCandidateToFirst;
- localStream.getTracks().forEach(function(track) {
- gFirstConnection.addTrack(track, localStream);
- });
- gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
-
- var videoTag = document.getElementById('local-view');
- videoTag.srcObject = localStream;
- };
-
- var onOfferCreated = test.step_func(function(offer) {
- gFirstConnection.setLocalDescription(offer);
-
- // remove all a=ssrc: lines and the (obsolete) msid-semantic line.
- var sdp = offer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
- .replace(/^a=msid-semantic.*$\r\n/gm, '');
-
- // This would normally go across the application's signaling solution.
- // In our case, the "signaling" is to call this function.
- receiveCall(sdp);
- });
-
- function receiveCall(offerSdp) {
- gSecondConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gSecondConnection.close());
- gSecondConnection.onicecandidate = onIceCandidateToSecond;
- gSecondConnection.ontrack = onRemoteTrack;
-
- var parsedOffer = new RTCSessionDescription({ type: 'offer',
- sdp: offerSdp });
- gSecondConnection.setRemoteDescription(parsedOffer);
-
- gSecondConnection.createAnswer().then(onAnswerCreated,
- failed('createAnswer'));
- };
-
- var onAnswerCreated = test.step_func(function(answer) {
- gSecondConnection.setLocalDescription(answer);
-
- // remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
- var sdp = answer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
- .replace(/^a=msid-semantic.*$\r\n/gm, '')
- .replace(/^a=msid:.*$\r\n/gm, '');
-
- // Similarly, this would go over the application's signaling solution.
- handleAnswer(sdp);
- });
-
- function handleAnswer(answerSdp) {
- var parsedAnswer = new RTCSessionDescription({ type: 'answer',
- sdp: answerSdp });
- gFirstConnection.setRemoteDescription(parsedAnswer);
- };
-
- var onIceCandidateToFirst = test.step_func(function(event) {
- gSecondConnection.addIceCandidate(event.candidate);
- });
-
- var onIceCandidateToSecond = test.step_func(function(event) {
- gFirstConnection.addIceCandidate(event.candidate);
- });
-
- var onRemoteTrack = test.step_func(function(event) {
- var videoTag = document.getElementById('remote-view');
- if (!videoTag.srcObject) {
- videoTag.srcObject = event.streams[0];
- }
- });
-
- // Returns a suitable error callback.
- function failed(function_name) {
- return test.unreached_func('WebRTC called error callback for ' + function_name);
- }
-
- // This function starts the test.
- test.step(function() {
- getNoiseStream({ video: true, audio: true })
- .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
- });
-</script>
-
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<html>
-<head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>RTCPeerConnection Connection Test</title>
- <script src="support/RTCPeerConnection-helper.js"></script>
-</head>
-<body>
- <div id="log"></div>
- <div>
- <video id="local-view" muted autoplay="autoplay"></video>
- <video id="remote-view" muted autoplay="autoplay"/>
- </video>
- </div>
-
- <!-- These files are in place when executing on W3C. -->
- <script src="../resources/testharness.js"></script>
- <script src="../resources/testharnessreport.js"></script>
- <script type="text/javascript">
- var test = async_test('Can set up a basic WebRTC call.');
-
- var gFirstConnection = null;
- var gSecondConnection = null;
-
- // if the remote video gets video data that implies the negotiation
- // as well as the ICE and DTLS connection are up.
- document.getElementById('remote-view')
- .addEventListener('loadedmetadata', function() {
- // Call negotiated: done.
- test.done();
- });
-
- function getNoiseStreamOkCallback(localStream) {
- gFirstConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gFirstConnection.close());
- gFirstConnection.onicecandidate = onIceCandidateToFirst;
- localStream.getTracks().forEach(function(track) {
- gFirstConnection.addTrack(track, localStream);
- });
- gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
-
- var videoTag = document.getElementById('local-view');
- videoTag.srcObject = localStream;
- };
-
- var onOfferCreated = test.step_func(function(offer) {
- gFirstConnection.setLocalDescription(offer);
-
- // This would normally go across the application's signaling solution.
- // In our case, the "signaling" is to call this function.
- receiveCall(offer.sdp);
- });
-
- function receiveCall(offerSdp) {
- gSecondConnection = new RTCPeerConnection(null);
- test.add_cleanup(() => gSecondConnection.close());
- gSecondConnection.onicecandidate = onIceCandidateToSecond;
- gSecondConnection.ontrack = onRemoteTrack;
-
- var parsedOffer = new RTCSessionDescription({ type: 'offer',
- sdp: offerSdp });
- gSecondConnection.setRemoteDescription(parsedOffer);
-
- gSecondConnection.createAnswer().then(onAnswerCreated,
- failed('createAnswer'));
- };
-
- var onAnswerCreated = test.step_func(function(answer) {
- gSecondConnection.setLocalDescription(answer);
-
- // Similarly, this would go over the application's signaling solution.
- handleAnswer(answer.sdp);
- });
-
- function handleAnswer(answerSdp) {
- var parsedAnswer = new RTCSessionDescription({ type: 'answer',
- sdp: answerSdp });
- gFirstConnection.setRemoteDescription(parsedAnswer);
- };
-
- var onIceCandidateToFirst = test.step_func(function(event) {
- gSecondConnection.addIceCandidate(event.candidate);
- });
-
- var onIceCandidateToSecond = test.step_func(function(event) {
- gFirstConnection.addIceCandidate(event.candidate);
- });
-
- var onRemoteTrack = test.step_func(function(event) {
- var videoTag = document.getElementById('remote-view');
- if (!videoTag.srcObject) {
- videoTag.srcObject = event.streams[0];
- }
- });
-
- // Returns a suitable error callback.
- function failed(function_name) {
- return test.unreached_func('WebRTC called error callback for ' + function_name);
- }
-
- // This function starts the test.
- test.step(function() {
- getNoiseStream({ video: true, audio: true })
- .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
- });
-</script>
-
-</body>
-</html>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Tests</title>
-<meta name="timeout" content="long">
-<script src="../third_party/sdp/sdp.js"></script>
-<script src="simulcast.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
-promise_test(async t => {
- const rids = [0, 1];
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
-}, 'Basic simulcast setup with two spatial layers');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Tests - getStats</title>
-<meta name="timeout" content="long">
-<script src="../third_party/sdp/sdp.js"></script>
-<script src="simulcast.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
-promise_test(async t => {
- const rids = [0, 1, 2];
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- await negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
-
- const outboundStats = [];
- const senderStats = await pc1.getSenders()[0].getStats();
- senderStats.forEach(stat => {
- if (stat.type === 'outbound-rtp') {
- outboundStats.push(stat);
- }
- });
- assert_equals(outboundStats.length, 3, "getStats result should contain three layers");
- const statsRids = outboundStats.map(stat => parseInt(stat.rid, 10));
- assert_array_equals(rids, statsRids.sort(), "getStats result should match the rids provided");
-}, 'Simulcast getStats results');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Tests</title>
-<meta name="timeout" content="long">
-<script src="../third_party/sdp/sdp.js"></script>
-<script src="simulcast.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
-/*
- * Chromium note: this requires build bots with H264 support. See
- * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
- * for details on how to enable support.
- */
-promise_test(async t => {
- assert_implements('getCapabilities' in RTCRtpSender, 'RTCRtpSender.getCapabilities not supported');
- assert_implements(RTCRtpSender.getCapabilities('video').codecs.find(c => c.mimeType === 'video/H264'), 'H264 not supported');
-
- const rids = [0, 1];
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, {mimeType: 'video/H264'});
-}, 'H264 simulcast setup with two spatial layers');
-</script>
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Tests - setParameters/active</title>
-<meta name="timeout" content="long">
-<script src="../third_party/sdp/sdp.js"></script>
-<script src="simulcast.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
-async function queryReceiverStats(pc) {
- const inboundStats = [];
- await Promise.all(pc.getReceivers().map(async receiver => {
- const receiverStats = await receiver.getStats();
- receiverStats.forEach(stat => {
- if (stat.type === 'inbound-rtp') {
- inboundStats.push(stat);
- }
- });
- }));
- return inboundStats.map(s => s.framesDecoded);
-}
-
-promise_test(async t => {
- const rids = [0, 1];
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- await negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
-
- // Deactivate all senders.
- const parameters = pc1.getSenders()[0].getParameters();
- parameters.encodings.forEach(e => {
- e.active = false;
- });
- await pc1.getSenders()[0].setParameters(parameters);
-
- // Assert (almost) no new frames are received.
- // Without any action we would expect to have received around 30fps.
- await new Promise(resolve => t.step_timeout(resolve, 100)); // Wait a bit.
- const initialStats = await queryReceiverStats(pc2);
- await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
- const subsequentStats = await queryReceiverStats(pc2);
-
- subsequentStats.forEach((framesDecoded, idx) => {
- assert_equals(framesDecoded, initialStats[idx]);
- });
-}, 'Simulcast setParameters active=false stops sending frames');
-</script>
+++ /dev/null
-'use strict';
-/* Helper functions to munge SDP and split the sending track into
- * separate tracks on the receiving end. This can be done in a number
- * of ways, the one used here uses the fact that the MID and RID header
- * extensions which are used for packet routing share the same wire
- * format. The receiver interprets the rids from the sender as mids
- * which allows receiving the different spatial resolutions on separate
- * m-lines and tracks.
- */
-const extensionsToFilter = [
- 'urn:ietf:params:rtp-hdrext:sdes:mid',
- 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id',
- 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id',
-];
-
-function swapRidAndMidExtensionsInSimulcastOffer(offer, rids) {
- const sections = SDPUtils.splitSections(offer.sdp);
- const dtls = SDPUtils.getDtlsParameters(sections[1], sections[0]);
- const ice = SDPUtils.getIceParameters(sections[1], sections[0]);
- const rtpParameters = SDPUtils.parseRtpParameters(sections[1]);
-
- // The gist of this hack is that rid and mid have the same wire format.
- const rid = rtpParameters.headerExtensions.find(ext => ext.uri === 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id');
- rtpParameters.headerExtensions = rtpParameters.headerExtensions.filter(ext => {
- return !extensionsToFilter.includes(ext.uri);
- });
- // This tells the other side that the RID packets are actually mids.
- rtpParameters.headerExtensions.push({id: rid.id, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid', direction: 'sendrecv'});
-
- // Filter rtx as we have no way to (re)interpret rrid.
- // Not doing this makes probing use RTX, it's not understood and ramp-up is slower.
- rtpParameters.codecs = rtpParameters.codecs.filter(c => c.name.toUpperCase() !== 'RTX');
-
- let sdp = SDPUtils.writeSessionBoilerplate() +
- SDPUtils.writeDtlsParameters(dtls, 'actpass') +
- SDPUtils.writeIceParameters(ice) +
- 'a=group:BUNDLE ' + rids.join(' ') + '\r\n';
- const baseRtpDescription = SDPUtils.writeRtpDescription('video', rtpParameters);
- rids.forEach(rid => {
- sdp += baseRtpDescription +
- 'a=mid:' + rid + '\r\n' +
- 'a=msid:rid-' + rid + ' rid-' + rid + '\r\n';
- });
- return sdp;
-}
-
-function swapRidAndMidExtensionsInSimulcastAnswer(answer, localDescription, rids) {
- const sections = SDPUtils.splitSections(answer.sdp);
- const dtls = SDPUtils.getDtlsParameters(sections[1], sections[0]);
- const ice = SDPUtils.getIceParameters(sections[1], sections[0]);
- const rtpParameters = SDPUtils.parseRtpParameters(sections[1]);
-
- rtpParameters.headerExtensions = rtpParameters.headerExtensions.filter(ext => {
- return !extensionsToFilter.includes(ext.uri);
- });
- const localMid = SDPUtils.getMid(SDPUtils.splitSections(localDescription.sdp)[1]);
- let sdp = SDPUtils.writeSessionBoilerplate() +
- SDPUtils.writeDtlsParameters(dtls, 'active') +
- SDPUtils.writeIceParameters(ice) +
- 'a=group:BUNDLE ' + localMid + '\r\n';
- sdp += SDPUtils.writeRtpDescription('video', rtpParameters);
- sdp += 'a=mid:' + localMid + '\r\n';
-
- rids.forEach(rid => {
- sdp += 'a=rid:' + rid + ' recv\r\n';
- });
- sdp += 'a=simulcast:recv ' + rids.join(';') + '\r\n';
-
- // Re-add headerextensions we filtered.
- const headerExtensions = SDPUtils.parseRtpParameters(SDPUtils.splitSections(localDescription.sdp)[1]).headerExtensions;
- headerExtensions.forEach(ext => {
- if (extensionsToFilter.includes(ext.uri)) {
- sdp += 'a=extmap:' + ext.id + ' ' + ext.uri + '\r\n';
- }
- });
- return sdp;
-}
-
-async function negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, codec) {
- exchangeIceCandidates(pc1, pc2);
-
- const metadataToBeLoaded = [];
- pc2.ontrack = (e) => {
- const stream = e.streams[0];
- const v = document.createElement('video');
- v.autoplay = true;
- v.srcObject = stream;
- v.id = stream.id
- metadataToBeLoaded.push(new Promise((resolve) => {
- v.addEventListener('loadedmetadata', () => {
- resolve();
- });
- }));
- };
-
- const sendEncodings = rids.map(rid => ({rid}));
- // Use a 2X downscale factor between each layer. To improve ramp-up time, the
- // top layer is scaled down by a factor 2. Smaller layer comes first. For
- // example if MediaStreamTrack is 720p and we want to send three layers we'll
- // get {90p, 180p, 360p}.
- let scaleResolutionDownBy = 2;
- for (let i = sendEncodings.length - 1; i >= 0; --i) {
- sendEncodings[i].scaleResolutionDownBy = scaleResolutionDownBy;
- scaleResolutionDownBy *= 2;
- }
- // Use getUserMedia as getNoiseStream does not have enough entropy to ramp-up.
- await setMediaPermission();
- const stream = await navigator.mediaDevices.getUserMedia({video: {width: 1280, height: 720}});
- t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
- const transceiver = pc1.addTransceiver(stream.getVideoTracks()[0], {
- streams: [stream],
- sendEncodings: sendEncodings,
- });
- if (codec) {
- preferCodec(transceiver, codec.mimeType, codec.sdpFmtpLine);
- }
- const offer = await pc1.createOffer();
- await pc1.setLocalDescription(offer),
- await pc2.setRemoteDescription({
- type: 'offer',
- sdp: swapRidAndMidExtensionsInSimulcastOffer(offer, rids),
- });
- const answer = await pc2.createAnswer();
- await pc2.setLocalDescription(answer);
- await pc1.setRemoteDescription({
- type: 'answer',
- sdp: swapRidAndMidExtensionsInSimulcastAnswer(answer, pc1.localDescription, rids),
- });
- assert_equals(metadataToBeLoaded.length, rids.length);
- return Promise.all(metadataToBeLoaded);
-}
+++ /dev/null
-<!doctype html>
-<meta charset=utf-8>
-<title>RTCPeerConnection Simulcast Tests</title>
-<meta name="timeout" content="long">
-<script src="../third_party/sdp/sdp.js"></script>
-<script src="simulcast.js"></script>
-<script src="../support/RTCPeerConnection-helper.js"></script>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../../resources/testdriver.js"></script>
-<script src="../../resources/testdriver-vendor.js"></script>
-<script src="../support/permission-helper.js"></script>
-<script>
-promise_test(async t => {
- assert_implements('getCapabilities' in RTCRtpSender, 'RTCRtpSender.getCapabilities not supported');
- assert_implements(RTCRtpSender.getCapabilities('video').codecs.find(c => c.mimeType === 'video/VP8'), 'VP8 not supported');
-
- const rids = [0, 1];
- const pc1 = new RTCPeerConnection();
- t.add_cleanup(() => pc1.close());
- const pc2 = new RTCPeerConnection();
- t.add_cleanup(() => pc2.close());
-
- return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, {mimeType: 'video/VP8'});
-}, 'VP8 simulcast setup with two spatial layers');
-</script>
+++ /dev/null
-'use strict';
-
-// Run a test function as two test cases.
-// The first test case test the configuration by passing a given config
-// to the constructor.
-// The second test case create an RTCPeerConnection object with default
-// configuration, then call setConfiguration with the provided config.
-// The test function is given a constructor function to create
-// a new instance of RTCPeerConnection with given config,
-// either directly as constructor parameter or through setConfiguration.
-function config_test(test_func, desc) {
- test(() => {
- test_func(config => new RTCPeerConnection(config));
- }, `new RTCPeerConnection(config) - ${desc}`);
-
- test(() => {
- test_func(config => {
- const pc = new RTCPeerConnection();
- assert_idl_attribute(pc, 'setConfiguration');
- pc.setConfiguration(config);
- return pc;
- })
- }, `setConfiguration(config) - ${desc}`);
-}
+++ /dev/null
-'use strict';
-
-// Test is based on the following editor draft:
-// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-// Code using this helper should also include RTCPeerConnection-helper.js
-// in the main HTML file
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// getTrackFromUserMedia
-// exchangeOfferAnswer
-
-// Create a RTCDTMFSender using getUserMedia()
-// Connect the PeerConnection to another PC and wait until it is
-// properly connected, so that DTMF can be sent.
-function createDtmfSender(pc = new RTCPeerConnection()) {
- let dtmfSender;
- return getTrackFromUserMedia('audio')
- .then(([track, mediaStream]) => {
- const sender = pc.addTrack(track, mediaStream);
- dtmfSender = sender.dtmf;
- assert_true(dtmfSender instanceof RTCDTMFSender,
- 'Expect audio sender.dtmf to be set to a RTCDTMFSender');
- // Note: spec bug open - https://github.com/w3c/webrtc-pc/issues/1774
- // on whether sending should be possible before negotiation.
- const pc2 = new RTCPeerConnection();
- Object.defineProperty(pc, 'otherPc', { value: pc2 });
- exchangeIceCandidates(pc, pc2);
- return exchangeOfferAnswer(pc, pc2);
- }).then(() => {
- if (!('canInsertDTMF' in dtmfSender)) {
- return Promise.resolve();
- }
- // Wait until dtmfSender.canInsertDTMF becomes true.
- // Up to 150 ms has been observed in test. Wait 1 second
- // in steps of 10 ms.
- // Note: Using a short timeout and rejected promise in order to
- // make test return a clear error message on failure.
- return new Promise((resolve, reject) => {
- let counter = 0;
- step_timeout(function checkCanInsertDTMF() {
- if (dtmfSender.canInsertDTMF) {
- resolve();
- } else {
- if (counter >= 100) {
- reject('Waited too long for canInsertDTMF');
- return;
- }
- ++counter;
- step_timeout(checkCanInsertDTMF, 10);
- }
- }, 0);
- });
- }).then(() => {
- return dtmfSender;
- });
-}
-
-/*
- Create an RTCDTMFSender and test tonechange events on it.
- testFunc
- Test function that is going to manipulate the DTMFSender.
- It will be called with:
- t - the test object
- sender - the created RTCDTMFSender
- pc - the associated RTCPeerConnection as second argument.
- toneChanges
- Array of expected tonechange events fired. The elements
- are array of 3 items:
- expectedTone
- The expected character in event.tone
- expectedToneBuffer
- The expected new value of dtmfSender.toneBuffer
- expectedDuration
- The rough time since beginning or last tonechange event
- was fired.
- desc
- Test description.
- */
-function test_tone_change_events(testFunc, toneChanges, desc) {
- // Convert to cumulative time
- let cumulativeTime = 0;
- const cumulativeToneChanges = toneChanges.map(c => {
- cumulativeTime += c[2];
- return [c[0], c[1], cumulativeTime];
- });
-
- // Wait for same duration as last expected duration + 100ms
- // before passing test in case there are new tone events fired,
- // in which case the test should fail.
- const lastWait = toneChanges.pop()[2] + 100;
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- const dtmfSender = await createDtmfSender(pc);
- const start = Date.now();
-
- const allEventsReceived = new Promise(resolve => {
- const onToneChange = t.step_func(ev => {
- assert_true(ev instanceof RTCDTMFToneChangeEvent,
- 'Expect tone change event object to be an RTCDTMFToneChangeEvent');
-
- const { tone } = ev;
- assert_equals(typeof tone, 'string',
- 'Expect event.tone to be the tone string');
-
- assert_greater_than(cumulativeToneChanges.length, 0,
- 'More tonechange event is fired than expected');
-
- const [
- expectedTone, expectedToneBuffer, expectedTime
- ] = cumulativeToneChanges.shift();
-
- assert_equals(tone, expectedTone,
- `Expect current event.tone to be ${expectedTone}`);
-
- assert_equals(dtmfSender.toneBuffer, expectedToneBuffer,
- `Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`);
-
- // We check that the cumulative delay is at least the expected one, but
- // system load may cause random delays, so we do not put any
- // realistic upper bound on the timing of the events.
- assert_between_inclusive(Date.now() - start, expectedTime,
- expectedTime + 4000,
- `Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`);
- if (cumulativeToneChanges.length === 0) {
- resolve();
- }
- });
-
- dtmfSender.addEventListener('tonechange', onToneChange);
- });
-
- testFunc(t, dtmfSender, pc);
- await allEventsReceived;
- const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms));
- await wait(lastWait);
- }, desc);
-}
-
-// Get the one and only tranceiver from pc.getTransceivers().
-// Assumes that there is only one tranceiver in pc.
-function getTransceiver(pc) {
- const transceivers = pc.getTransceivers();
- assert_equals(transceivers.length, 1,
- 'Expect there to be only one tranceiver in pc');
-
- return transceivers[0];
-}
+++ /dev/null
-'use strict';
-
-const validBinaryTypes = ['blob', 'arraybuffer'];
-const invalidBinaryTypes = ['jellyfish', 'arraybuffer ', '', null, undefined];
-
-for (const binaryType of validBinaryTypes) {
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const dc = pc.createDataChannel('test-binary-type');
-
- dc.binaryType = binaryType;
- assert_equals(dc.binaryType, binaryType, `dc.binaryType should be '${binaryType}'`);
- }, `Setting binaryType to '${binaryType}' should succeed`);
-}
-
-for (const binaryType of invalidBinaryTypes) {
- test((t) => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const dc = pc.createDataChannel('test-binary-type');
-
- assert_throws_dom('SyntaxError', () => {
- dc.binaryType = binaryType;
- });
- }, `Setting invalid binaryType '${binaryType}' should throw SyntaxError`);
-}
+++ /dev/null
-'use strict'
-
-/*
- * Helper Methods for testing the following methods in RTCPeerConnection:
- * createOffer
- * createAnswer
- * setLocalDescription
- * setRemoteDescription
- *
- * This file offers the following features:
- * SDP similarity comparison
- * Generating offer/answer using anonymous peer connection
- * Test signalingstatechange event
- * Test promise that never resolve
- */
-
-const audioLineRegex = /\r\nm=audio.+\r\n/g;
-const videoLineRegex = /\r\nm=video.+\r\n/g;
-const applicationLineRegex = /\r\nm=application.+\r\n/g;
-
-function countLine(sdp, regex) {
- const matches = sdp.match(regex);
- if(matches === null) {
- return 0;
- } else {
- return matches.length;
- }
-}
-
-function countAudioLine(sdp) {
- return countLine(sdp, audioLineRegex);
-}
-
-function countVideoLine(sdp) {
- return countLine(sdp, videoLineRegex);
-}
-
-function countApplicationLine(sdp) {
- return countLine(sdp, applicationLineRegex);
-}
-
-function similarMediaDescriptions(sdp1, sdp2) {
- if(sdp1 === sdp2) {
- return true;
- } else if(
- countAudioLine(sdp1) !== countAudioLine(sdp2) ||
- countVideoLine(sdp1) !== countVideoLine(sdp2) ||
- countApplicationLine(sdp1) !== countApplicationLine(sdp2))
- {
- return false;
- } else {
- return true;
- }
-}
-
-// Assert that given object is either an
-// RTCSessionDescription or RTCSessionDescriptionInit
-function assert_is_session_description(sessionDesc) {
- if(sessionDesc instanceof RTCSessionDescription) {
- return;
- }
-
- assert_not_equals(sessionDesc, undefined,
- 'Expect session description to be defined');
-
- assert_true(typeof(sessionDesc) === 'object',
- 'Expect sessionDescription to be either a RTCSessionDescription or an object');
-
- assert_true(typeof(sessionDesc.type) === 'string',
- 'Expect sessionDescription.type to be a string');
-
- assert_true(typeof(sessionDesc.sdp) === 'string',
- 'Expect sessionDescription.sdp to be a string');
-}
-
-
-// We can't do string comparison to the SDP content,
-// because RTCPeerConnection may return SDP that is
-// slightly modified or reordered from what is given
-// to it due to ICE candidate events or serialization.
-// Instead, we create SDP with different number of media
-// lines, and if the SDP strings are not the same, we
-// simply count the media description lines and if they
-// are the same, we assume it is the same.
-function isSimilarSessionDescription(sessionDesc1, sessionDesc2) {
- assert_is_session_description(sessionDesc1);
- assert_is_session_description(sessionDesc2);
-
- if(sessionDesc1.type !== sessionDesc2.type) {
- return false;
- } else {
- return similarMediaDescriptions(sessionDesc1.sdp, sessionDesc2.sdp);
- }
-}
-
-function assert_session_desc_similar(sessionDesc1, sessionDesc2) {
- assert_true(isSimilarSessionDescription(sessionDesc1, sessionDesc2),
- 'Expect both session descriptions to have the same count of media lines');
-}
-
-function assert_session_desc_not_similar(sessionDesc1, sessionDesc2) {
- assert_false(isSimilarSessionDescription(sessionDesc1, sessionDesc2),
- 'Expect both session descriptions to have different count of media lines');
-}
-
-async function generateDataChannelOffer(pc) {
- pc.createDataChannel('test');
- const offer = await pc.createOffer();
- assert_equals(countApplicationLine(offer.sdp), 1, 'Expect m=application line to be present in generated SDP');
- return offer;
-}
-
-async function generateAudioReceiveOnlyOffer(pc)
-{
- try {
- pc.addTransceiver('audio', { direction: 'recvonly' });
- return pc.createOffer();
- } catch(e) {
- return pc.createOffer({ offerToReceiveAudio: true });
- }
-}
-
-async function generateVideoReceiveOnlyOffer(pc)
-{
- try {
- pc.addTransceiver('video', { direction: 'recvonly' });
- return pc.createOffer();
- } catch(e) {
- return pc.createOffer({ offerToReceiveVideo: true });
- }
-}
-
-// Helper function to generate answer based on given offer using a freshly
-// created RTCPeerConnection object
-async function generateAnswer(offer) {
- const pc = new RTCPeerConnection();
- await pc.setRemoteDescription(offer);
- const answer = await pc.createAnswer();
- pc.close();
- return answer;
-}
-
-// Helper function to generate offer using a freshly
-// created RTCPeerConnection object
-async function generateOffer() {
- const pc = new RTCPeerConnection();
- const offer = await pc.createOffer();
- pc.close();
- return offer;
-}
-
-// Run a test function that return a promise that should
-// never be resolved. For lack of better options,
-// we wait for a time out and pass the test if the
-// promise doesn't resolve within that time.
-function test_never_resolve(testFunc, testName) {
- async_test(t => {
- testFunc(t)
- .then(
- t.step_func(result => {
- assert_unreached(`Pending promise should never be resolved. Instead it is fulfilled with: ${result}`);
- }),
- t.step_func(err => {
- assert_unreached(`Pending promise should never be resolved. Instead it is rejected with: ${err}`);
- }));
-
- t.step_timeout(t.step_func_done(), 100)
- }, testName);
-}
-
-// Helper function to exchange ice candidates between
-// two local peer connections
-function exchangeIceCandidates(pc1, pc2) {
- // private function
- function doExchange(localPc, remotePc) {
- localPc.addEventListener('icecandidate', event => {
- const { candidate } = event;
-
- // Guard against already closed peerconnection to
- // avoid unrelated exceptions.
- if (remotePc.signalingState !== 'closed') {
- remotePc.addIceCandidate(candidate);
- }
- });
- }
-
- doExchange(pc1, pc2);
- doExchange(pc2, pc1);
-}
-
-// Returns a promise that resolves when a |name| event is fired.
-function waitUntilEvent(obj, name) {
- return new Promise(r => obj.addEventListener(name, r, {once: true}));
-}
-
-// Returns a promise that resolves when the |transport.state| is |state|
-// This should work for RTCSctpTransport, RTCDtlsTransport and RTCIceTransport.
-async function waitForState(transport, state) {
- while (transport.state != state) {
- await waitUntilEvent(transport, 'statechange');
- }
-}
-
-// Returns a promise that resolves when |pc.iceConnectionState| is 'connected'
-// or 'completed'.
-async function listenToIceConnected(pc) {
- await waitForIceStateChange(pc, ['connected', 'completed']);
-}
-
-// Returns a promise that resolves when |pc.iceConnectionState| is in one of the
-// wanted states.
-async function waitForIceStateChange(pc, wantedStates) {
- while (!wantedStates.includes(pc.iceConnectionState)) {
- await waitUntilEvent(pc, 'iceconnectionstatechange');
- }
-}
-
-// Returns a promise that resolves when |pc.connectionState| is 'connected'.
-async function listenToConnected(pc) {
- while (pc.connectionState != 'connected') {
- await waitUntilEvent(pc, 'connectionstatechange');
- }
-}
-
-// Returns a promise that resolves when |pc.connectionState| is in one of the
-// wanted states.
-async function waitForConnectionStateChange(pc, wantedStates) {
- while (!wantedStates.includes(pc.connectionState)) {
- await waitUntilEvent(pc, 'connectionstatechange');
- }
-}
-
-async function waitForIceGatheringState(pc, wantedStates) {
- while (!wantedStates.includes(pc.iceGatheringState)) {
- await waitUntilEvent(pc, 'icegatheringstatechange');
- }
-}
-
-// Resolves when RTP packets have been received.
-async function listenForSSRCs(t, receiver) {
- while (true) {
- const ssrcs = receiver.getSynchronizationSources();
- if (Array.isArray(ssrcs) && ssrcs.length > 0) {
- return ssrcs;
- }
- await new Promise(r => t.step_timeout(r, 0));
- }
-}
-
-// Helper function to create a pair of connected data channels.
-// On success the promise resolves to an array with two data channels.
-// It does the heavy lifting of performing signaling handshake,
-// ICE candidate exchange, and waiting for data channel at two
-// end points to open. Can do both negotiated and non-negotiated setup.
-async function createDataChannelPair(t, options,
- pc1 = createPeerConnectionWithCleanup(t),
- pc2 = createPeerConnectionWithCleanup(t)) {
- let pair = [], bothOpen;
- try {
- if (options.negotiated) {
- pair = [pc1, pc2].map(pc => pc.createDataChannel('', options));
- bothOpen = Promise.all(pair.map(dc => new Promise((r, e) => {
- dc.onopen = r;
- dc.onerror = ({error}) => e(error);
- })));
- } else {
- pair = [pc1.createDataChannel('', options)];
- bothOpen = Promise.all([
- new Promise((r, e) => {
- pair[0].onopen = r;
- pair[0].onerror = ({error}) => e(error);
- }),
- new Promise((r, e) => pc2.ondatachannel = ({channel}) => {
- pair[1] = channel;
- channel.onopen = r;
- channel.onerror = ({error}) => e(error);
- })
- ]);
- }
- exchangeIceCandidates(pc1, pc2);
- await exchangeOfferAnswer(pc1, pc2);
- await bothOpen;
- return pair;
- } finally {
- for (const dc of pair) {
- dc.onopen = dc.onerror = null;
- }
- }
-}
-
-// Wait for RTP and RTCP stats to arrive
-async function waitForRtpAndRtcpStats(pc) {
- // If remote stats are never reported, return after 5 seconds.
- const startTime = performance.now();
- while (true) {
- const report = await pc.getStats();
- const stats = [...report.values()].filter(({type}) => type.endsWith("bound-rtp"));
- // Each RTP and RTCP stat has a reference
- // to the matching stat in the other direction
- if (stats.length && stats.every(({localId, remoteId}) => localId || remoteId)) {
- break;
- }
- if (performance.now() > startTime + 5000) {
- break;
- }
- }
-}
-
-// Wait for a single message event and return
-// a promise that resolve when the event fires
-function awaitMessage(channel) {
- const once = true;
- return new Promise((resolve, reject) => {
- channel.addEventListener('message', ({data}) => resolve(data), {once});
- channel.addEventListener('error', reject, {once});
- });
-}
-
-// Helper to convert a blob to array buffer so that
-// we can read the content
-async function blobToArrayBuffer(blob) {
- const reader = new FileReader();
- reader.readAsArrayBuffer(blob);
- return new Promise((resolve, reject) => {
- reader.addEventListener('load', () => resolve(reader.result), {once: true});
- reader.addEventListener('error', () => reject(reader.error), {once: true});
- });
-}
-
-// Assert that two TypedArray or ArrayBuffer objects have the same byte values
-function assert_equals_typed_array(array1, array2) {
- const [view1, view2] = [array1, array2].map((array) => {
- if (array instanceof ArrayBuffer) {
- return new DataView(array);
- } else {
- assert_true(array.buffer instanceof ArrayBuffer,
- 'Expect buffer to be instance of ArrayBuffer');
- return new DataView(array.buffer, array.byteOffset, array.byteLength);
- }
- });
-
- assert_equals(view1.byteLength, view2.byteLength,
- 'Expect both arrays to be of the same byte length');
-
- const byteLength = view1.byteLength;
-
- for (let i = 0; i < byteLength; ++i) {
- assert_equals(view1.getUint8(i), view2.getUint8(i),
- `Expect byte at buffer position ${i} to be equal`);
- }
-}
-
-// These media tracks will be continually updated with deterministic "noise" in
-// order to ensure UAs do not cease transmission in response to apparent
-// silence.
-//
-// > Many codecs and systems are capable of detecting "silence" and changing
-// > their behavior in this case by doing things such as not transmitting any
-// > media.
-//
-// Source: https://w3c.github.io/webrtc-pc/#offer-answer-options
-const trackFactories = {
- // Share a single context between tests to avoid exceeding resource limits
- // without requiring explicit destruction.
- audioContext: null,
-
- /**
- * Given a set of requested media types, determine if the user agent is
- * capable of procedurally generating a suitable media stream.
- *
- * @param {object} requested
- * @param {boolean} [requested.audio] - flag indicating whether the desired
- * stream should include an audio track
- * @param {boolean} [requested.video] - flag indicating whether the desired
- * stream should include a video track
- *
- * @returns {boolean}
- */
- canCreate(requested) {
- const supported = {
- audio: !!window.AudioContext && !!window.MediaStreamAudioDestinationNode,
- video: !!HTMLCanvasElement.prototype.captureStream
- };
-
- return (!requested.audio || supported.audio) &&
- (!requested.video || supported.video);
- },
-
- audio() {
- const ctx = trackFactories.audioContext = trackFactories.audioContext ||
- new AudioContext();
- const oscillator = ctx.createOscillator();
- const dst = oscillator.connect(ctx.createMediaStreamDestination());
- oscillator.start();
- return dst.stream.getAudioTracks()[0];
- },
-
- video({width = 640, height = 480, signal} = {}) {
- const canvas = Object.assign(
- document.createElement("canvas"), {width, height}
- );
- const ctx = canvas.getContext('2d');
- const stream = canvas.captureStream();
-
- let count = 0;
- const interval = setInterval(() => {
- ctx.fillStyle = `rgb(${count%255}, ${count*count%255}, ${count%255})`;
- count += 1;
- ctx.fillRect(0, 0, width, height);
- // Add some bouncing boxes in contrast color to add a little more noise.
- const contrast = count + 128;
- ctx.fillStyle = `rgb(${contrast%255}, ${contrast*contrast%255}, ${contrast%255})`;
- const xpos = count % (width - 20);
- const ypos = count % (height - 20);
- ctx.fillRect(xpos, ypos, xpos + 20, ypos + 20);
- const xpos2 = (count + width / 2) % (width - 20);
- const ypos2 = (count + height / 2) % (height - 20);
- ctx.fillRect(xpos2, ypos2, xpos2 + 20, ypos2 + 20);
- // If signal is set (0-255), add a constant-color box of that luminance to
- // the video frame at coordinates 20 to 60 in both X and Y direction.
- // (big enough to avoid color bleed from surrounding video in some codecs,
- // for more stable tests).
- if (signal != undefined) {
- ctx.fillStyle = `rgb(${signal}, ${signal}, ${signal})`;
- ctx.fillRect(20, 20, 40, 40);
- }
- }, 100);
-
- if (document.body) {
- document.body.appendChild(canvas);
- } else {
- document.addEventListener('DOMContentLoaded', () => {
- document.body.appendChild(canvas);
- }, {once: true});
- }
-
- // Implement track.stop() for performance in some tests on some platforms
- const track = stream.getVideoTracks()[0];
- const nativeStop = track.stop;
- track.stop = function stop() {
- clearInterval(interval);
- nativeStop.apply(this);
- if (document.body && canvas.parentElement == document.body) {
- document.body.removeChild(canvas);
- }
- };
- return track;
- }
-};
-
-// Get the signal from a video element inserted by createNoiseStream
-function getVideoSignal(v) {
- if (v.videoWidth < 60 || v.videoHeight < 60) {
- throw new Error('getVideoSignal: video too small for test');
- }
- const canvas = document.createElement("canvas");
- canvas.width = canvas.height = 60;
- const context = canvas.getContext('2d');
- context.drawImage(v, 0, 0);
- // Extract pixel value at position 40, 40
- const pixel = context.getImageData(40, 40, 1, 1);
- // Use luma reconstruction to get back original value according to
- // ITU-R rec BT.709
- return (pixel.data[0] * 0.21 + pixel.data[1] * 0.72 + pixel.data[2] * 0.07);
-}
-
-async function detectSignal(t, v, value) {
- while (true) {
- const signal = getVideoSignal(v).toFixed();
- // allow off-by-two pixel error (observed in some implementations)
- if (value - 2 <= signal && signal <= value + 2) {
- return;
- }
- // We would like to wait for each new frame instead here,
- // but there seems to be no such callback.
- await new Promise(r => t.step_timeout(r, 100));
- }
-}
-
-// Generate a MediaStream bearing the specified tracks.
-//
-// @param {object} [caps]
-// @param {boolean} [caps.audio] - flag indicating whether the generated stream
-// should include an audio track
-// @param {boolean} [caps.video] - flag indicating whether the generated stream
-// should include a video track, or parameters for video
-async function getNoiseStream(caps = {}) {
- if (!trackFactories.canCreate(caps)) {
- return navigator.mediaDevices.getUserMedia(caps);
- }
- const tracks = [];
-
- if (caps.audio) {
- tracks.push(trackFactories.audio());
- }
-
- if (caps.video) {
- tracks.push(trackFactories.video(caps.video));
- }
-
- return new MediaStream(tracks);
-}
-
-// Obtain a MediaStreamTrack of kind using procedurally-generated streams (and
-// falling back to `getUserMedia` when the user agent cannot generate the
-// requested streams).
-// Return Promise of pair of track and associated mediaStream.
-// Assumes that there is at least one available device
-// to generate the track.
-function getTrackFromUserMedia(kind) {
- return getNoiseStream({ [kind]: true })
- .then(mediaStream => {
- const [track] = mediaStream.getTracks();
- return [track, mediaStream];
- });
-}
-
-// Obtain |count| MediaStreamTracks of type |kind| and MediaStreams. The tracks
-// do not belong to any stream and the streams are empty. Returns a Promise
-// resolved with a pair of arrays [tracks, streams].
-// Assumes there is at least one available device to generate the tracks and
-// streams and that the getUserMedia() calls resolve.
-function getUserMediaTracksAndStreams(count, type = 'audio') {
- let otherTracksPromise;
- if (count > 1)
- otherTracksPromise = getUserMediaTracksAndStreams(count - 1, type);
- else
- otherTracksPromise = Promise.resolve([[], []]);
- return otherTracksPromise.then(([tracks, streams]) => {
- return getTrackFromUserMedia(type)
- .then(([track, stream]) => {
- // Remove the default stream-track relationship.
- stream.removeTrack(track);
- tracks.push(track);
- streams.push(stream);
- return [tracks, streams];
- });
- });
-}
-
-// Performs an offer exchange caller -> callee.
-async function exchangeOffer(caller, callee) {
- await caller.setLocalDescription(await caller.createOffer());
- await callee.setRemoteDescription(caller.localDescription);
-}
-// Performs an answer exchange caller -> callee.
-async function exchangeAnswer(caller, callee) {
- // Note that caller's remote description must be set first; if not,
- // there's a chance that candidates from callee arrive at caller before
- // it has a remote description to apply them to.
- const answer = await callee.createAnswer();
- await caller.setRemoteDescription(answer);
- await callee.setLocalDescription(answer);
-}
-async function exchangeOfferAnswer(caller, callee) {
- await exchangeOffer(caller, callee);
- await exchangeAnswer(caller, callee);
-}
-
-// The returned promise is resolved with caller's ontrack event.
-async function exchangeAnswerAndListenToOntrack(t, caller, callee) {
- const ontrackPromise = addEventListenerPromise(t, caller, 'track');
- await exchangeAnswer(caller, callee);
- return ontrackPromise;
-}
-// The returned promise is resolved with callee's ontrack event.
-async function exchangeOfferAndListenToOntrack(t, caller, callee) {
- const ontrackPromise = addEventListenerPromise(t, callee, 'track');
- await exchangeOffer(caller, callee);
- return ontrackPromise;
-}
-
-// The resolver extends a |promise| that can be resolved or rejected using |resolve|
-// or |reject|.
-class Resolver extends Promise {
- constructor(executor) {
- let resolve, reject;
- super((resolve_, reject_) => {
- resolve = resolve_;
- reject = reject_;
- if (executor) {
- return executor(resolve_, reject_);
- }
- });
-
- this._done = false;
- this._resolve = resolve;
- this._reject = reject;
- }
-
- /**
- * Return whether the promise is done (resolved or rejected).
- */
- get done() {
- return this._done;
- }
-
- /**
- * Resolve the promise.
- */
- resolve(...args) {
- this._done = true;
- return this._resolve(...args);
- }
-
- /**
- * Reject the promise.
- */
- reject(...args) {
- this._done = true;
- return this._reject(...args);
- }
-}
-
-function addEventListenerPromise(t, obj, type, listener) {
- if (!listener) {
- return waitUntilEvent(obj, type);
- }
- return new Promise(r => obj.addEventListener(type,
- t.step_func(e => r(listener(e))),
- {once: true}));
-}
-
-function createPeerConnectionWithCleanup(t) {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- return pc;
-}
-
-async function createTrackAndStreamWithCleanup(t, kind = 'audio') {
- let constraints = {};
- constraints[kind] = true;
- const stream = await getNoiseStream(constraints);
- const [track] = stream.getTracks();
- t.add_cleanup(() => track.stop());
- return [track, stream];
-}
-
-function findTransceiverForSender(pc, sender) {
- const transceivers = pc.getTransceivers();
- for (let i = 0; i < transceivers.length; ++i) {
- if (transceivers[i].sender == sender)
- return transceivers[i];
- }
- return null;
-}
-
-function preferCodec(transceiver, mimeType, sdpFmtpLine) {
- const {codecs} = RTCRtpSender.getCapabilities(transceiver.receiver.track.kind);
- // sdpFmtpLine is optional, pick the first partial match if not given.
- const selectedCodecIndex = codecs.findIndex(c => {
- return c.mimeType === mimeType && (c.sdpFmtpLine === sdpFmtpLine || !sdpFmtpLine);
- });
- const selectedCodec = codecs[selectedCodecIndex];
- codecs.slice(selectedCodecIndex, 1);
- codecs.unshift(selectedCodec);
- return transceiver.setCodecPreferences(codecs);
-}
-
-// Contains a set of values and will yell at you if you try to add a value twice.
-class UniqueSet extends Set {
- constructor(items) {
- super();
- if (items !== undefined) {
- for (const item of items) {
- this.add(item);
- }
- }
- }
-
- add(value, message) {
- if (message === undefined) {
- message = `Value '${value}' needs to be unique but it is already in the set`;
- }
- assert_true(!this.has(value), message);
- super.add(value);
- }
-}
-
-const iceGatheringStateTransitions = async (pc, ...states) => {
- for (const state of states) {
- await new Promise((resolve, reject) => {
- pc.addEventListener('icegatheringstatechange', () => {
- if (pc.iceGatheringState == state) {
- resolve();
- } else {
- reject(`Unexpected gathering state: ${pc.iceGatheringState}, was expecting ${state}`);
- }
- }, {once: true});
- });
- }
-};
-
-const initialOfferAnswerWithIceGatheringStateTransitions =
- async (pc1, pc2, offerOptions) => {
- await pc1.setLocalDescription(
- await pc1.createOffer(offerOptions));
- const pc1Transitions =
- iceGatheringStateTransitions(pc1, 'gathering', 'complete');
- await pc2.setRemoteDescription(pc1.localDescription);
- await pc2.setLocalDescription(await pc2.createAnswer());
- const pc2Transitions =
- iceGatheringStateTransitions(pc2, 'gathering', 'complete');
- await pc1.setRemoteDescription(pc2.localDescription);
- await pc1Transitions;
- await pc2Transitions;
- };
-
-const expectNoMoreGatheringStateChanges = async (t, pc) => {
- pc.onicegatheringstatechange =
- t.step_func(() => {
- assert_unreached(
- 'Should not get an icegatheringstatechange right now!');
- });
-};
+++ /dev/null
-'use strict'
-
-function peer(other, polite, fail = null) {
- const send = (tgt, msg) => tgt.postMessage(JSON.parse(JSON.stringify(msg)),
- "*");
- if (!fail) fail = e => send(window.parent, {error: `${e.name}: ${e.message}`});
- const pc = new RTCPeerConnection();
-
- if (!window.assert_equals) {
- window.assert_equals = (a, b, msg) => a === b ||
- fail(new Error(`${msg} expected ${b} but got ${a}`));
- }
-
- const commands = {
- async addTransceiver() {
- const transceiver = pc.addTransceiver("video");
- await new Promise(r => pc.addEventListener("negotiated", r, {once: true}));
- if (!transceiver.currentDirection) {
- // Might have just missed the negotiation train. Catch next one.
- await new Promise(r => pc.addEventListener("negotiated", r, {once: true}));
- }
- assert_equals(transceiver.currentDirection, "sendonly", "have direction");
- return pc.getTransceivers().length;
- },
- async simpleConnect() {
- const p = commands.addTransceiver();
- await new Promise(r => pc.oniceconnectionstatechange =
- () => pc.iceConnectionState == "connected" && r());
- return await p;
- },
- async getNumTransceivers() {
- return pc.getTransceivers().length;
- },
- };
-
- try {
- pc.addEventListener("icecandidate", ({candidate}) => send(other,
- {candidate}));
- let makingOffer = false, ignoreIceCandidateFailures = false;
- let srdAnswerPending = false;
- pc.addEventListener("negotiationneeded", async () => {
- try {
- assert_equals(pc.signalingState, "stable", "negotiationneeded always fires in stable state");
- assert_equals(makingOffer, false, "negotiationneeded not already in progress");
- makingOffer = true;
- await pc.setLocalDescription();
- assert_equals(pc.signalingState, "have-local-offer", "negotiationneeded not racing with onmessage");
- assert_equals(pc.localDescription.type, "offer", "negotiationneeded SLD worked");
- send(other, {description: pc.localDescription});
- } catch (e) {
- fail(e);
- } finally {
- makingOffer = false;
- }
- });
- window.onmessage = async ({data: {description, candidate, run}}) => {
- try {
- if (description) {
- // If we have a setRemoteDescription() answer operation pending, then
- // we will be "stable" by the time the next setRemoteDescription() is
- // executed, so we count this being stable when deciding whether to
- // ignore the offer.
- let isStable =
- pc.signalingState == "stable" ||
- (pc.signalingState == "have-local-offer" && srdAnswerPending);
- const ignoreOffer = description.type == "offer" && !polite &&
- (makingOffer || !isStable);
- if (ignoreOffer) {
- ignoreIceCandidateFailures = true;
- return;
- }
- if (description.type == "answer")
- srdAnswerPending = true;
- await pc.setRemoteDescription(description);
- ignoreIceCandidateFailures = false;
- srdAnswerPending = false;
- if (description.type == "offer") {
- assert_equals(pc.signalingState, "have-remote-offer", "Remote offer");
- assert_equals(pc.remoteDescription.type, "offer", "SRD worked");
- await pc.setLocalDescription();
- assert_equals(pc.signalingState, "stable", "onmessage not racing with negotiationneeded");
- assert_equals(pc.localDescription.type, "answer", "onmessage SLD worked");
- send(other, {description: pc.localDescription});
- } else {
- assert_equals(pc.remoteDescription.type, "answer", "Answer was set");
- assert_equals(pc.signalingState, "stable", "answered");
- pc.dispatchEvent(new Event("negotiated"));
- }
- } else if (candidate) {
- try {
- await pc.addIceCandidate(candidate);
- } catch (e) {
- if (!ignoreIceCandidateFailures) throw e;
- }
- } else if (run) {
- send(window.parent, {[run.id]: await commands[run.cmd]() || 0});
- }
- } catch (e) {
- fail(e);
- }
- };
- } catch (e) {
- fail(e);
- }
- return pc;
-}
-
-async function setupPeerIframe(t, polite) {
- const iframe = document.createElement("iframe");
- t.add_cleanup(() => iframe.remove());
- iframe.srcdoc =
- `<html\><script\>(${peer.toString()})(window.parent, ${polite});</script\></html\>`;
- document.documentElement.appendChild(iframe);
-
- const failCatcher = t.step_func(({data}) =>
- ("error" in data) && assert_unreached(`Error in iframe: ${data.error}`));
- window.addEventListener("message", failCatcher);
- t.add_cleanup(() => window.removeEventListener("message", failCatcher));
- await new Promise(r => iframe.onload = r);
- return iframe;
-}
-
-function setupPeerTopLevel(t, other, polite) {
- const pc = peer(other, polite, t.step_func(e => { throw e; }));
- t.add_cleanup(() => { pc.close(); window.onmessage = null; });
-}
-
-let counter = 0;
-async function run(target, cmd) {
- const id = `result${counter++}`;
- target.postMessage({run: {cmd, id}}, "*");
- return new Promise(r => window.addEventListener("message",
- function listen({data}) {
- if (!(id in data)) return;
- window.removeEventListener("message", listen);
- r(data[id]);
- }));
-}
-
-let iframe;
-async function setupAB(t, politeA, politeB) {
- iframe = await setupPeerIframe(t, politeB);
- return setupPeerTopLevel(t, iframe.contentWindow, politeA);
-}
-const runA = cmd => run(window, cmd);
-const runB = cmd => run(iframe.contentWindow, cmd);
-const runBoth = (cmdA, cmdB = cmdA) => Promise.all([runA(cmdA), runB(cmdB)]);
-
-async function promise_test_both_roles(f, name) {
- promise_test(async t => f(t, await setupAB(t, true, false)), name);
- promise_test(async t => f(t, await setupAB(t, false, true)),
- `${name} with roles reversed`);
-}
+++ /dev/null
-'use strict'
-
-// Test is based on the following editor draft:
-// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-// This file depends on dictionary-helper.js which should
-// be loaded from the main HTML file.
-
-/*
- 5.2. RTCRtpSender Interface
- dictionary RTCRtpCapabilities {
- sequence<RTCRtpCodecCapability> codecs;
- sequence<RTCRtpHeaderExtensionCapability> headerExtensions;
- };
-
- dictionary RTCRtpCodecCapability {
- DOMString mimeType;
- unsigned long clockRate;
- unsigned short channels;
- DOMString sdpFmtpLine;
- };
-
- dictionary RTCRtpHeaderExtensionCapability {
- DOMString uri;
- };
- */
-
-function validateRtpCapabilities(capabilities) {
- assert_array_field(capabilities, 'codecs');
- for(const codec of capabilities.codecs) {
- validateCodecCapability(codec);
- }
-
- assert_greater_than(capabilities.codecs.length, 0,
- 'Expect at least one codec capability available');
-
- assert_array_field(capabilities, 'headerExtensions');
- for(const headerExt of capabilities.headerExtensions) {
- validateHeaderExtensionCapability(headerExt);
- }
-}
-
-function validateCodecCapability(codec) {
- assert_optional_string_field(codec, 'mimeType');
- assert_optional_unsigned_int_field(codec, 'clockRate');
- assert_optional_unsigned_int_field(codec, 'channels');
- assert_optional_string_field(codec, 'sdpFmtpLine');
-}
-
-function validateHeaderExtensionCapability(headerExt) {
- assert_optional_string_field(headerExt, 'uri');
-}
+++ /dev/null
-'use strict';
-
-// Test is based on the following editor draft:
-// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
-
-// Helper function for testing RTCRtpParameters dictionary fields
-
-// This file depends on dictionary-helper.js which should
-// be loaded from the main HTML file.
-
-// An offer/answer exchange is necessary for getParameters() to have any
-// negotiated parameters to return.
-async function doOfferAnswerExchange(t, caller) {
- const callee = new RTCPeerConnection();
- t.add_cleanup(() => callee.close());
- const offer = await caller.createOffer();
- await caller.setLocalDescription(offer);
- await callee.setRemoteDescription(offer);
- const answer = await callee.createAnswer();
- await callee.setLocalDescription(answer);
- await caller.setRemoteDescription(answer);
-
- return callee;
-}
-
-/*
- Validates the RTCRtpParameters returned from RTCRtpSender.prototype.getParameters
-
- 5.2. RTCRtpSender Interface
- getParameters
- - transactionId is set to a new unique identifier, used to match this getParameters
- call to a setParameters call that may occur later.
-
- - encodings is set to the value of the [[SendEncodings]] internal slot.
-
- - The headerExtensions sequence is populated based on the header extensions that
- have been negotiated for sending.
-
- - The codecs sequence is populated based on the codecs that have been negotiated
- for sending, and which the user agent is currently capable of sending. If
- setParameters has removed or reordered codecs, getParameters MUST return the
- shortened/reordered list. However, every time codecs are renegotiated by a
- new offer/answer exchange, the list of codecs MUST be restored to the full
- negotiated set, in the priority order indicated by the remote description,
- in effect discarding the effects of setParameters.
-
- - rtcp.cname is set to the CNAME of the associated RTCPeerConnection. rtcp.reducedSize
- is set to true if reduced-size RTCP has been negotiated for sending, and false otherwise.
- */
-function validateSenderRtpParameters(param) {
- validateRtpParameters(param);
-
- assert_array_field(param, 'encodings');
- for(const encoding of param.encodings) {
- validateEncodingParameters(encoding);
- }
-
- assert_not_equals(param.transactionId, undefined,
- 'Expect sender param.transactionId to be set');
-
- assert_not_equals(param.rtcp.cname, undefined,
- 'Expect sender param.rtcp.cname to be set');
-
- assert_not_equals(param.rtcp.reducedSize, undefined,
- 'Expect sender param.rtcp.reducedSize to be set to either true or false');
-}
-
-/*
- Validates the RTCRtpParameters returned from RTCRtpReceiver.prototype.getParameters
-
- 5.3. RTCRtpReceiver Interface
- getParameters
- When getParameters is called, the RTCRtpParameters dictionary is constructed
- as follows:
-
- - The headerExtensions sequence is populated based on the header extensions that
- the receiver is currently prepared to receive.
-
- - The codecs sequence is populated based on the codecs that the receiver is currently
- prepared to receive.
-
- - rtcp.reducedSize is set to true if the receiver is currently prepared to receive
- reduced-size RTCP packets, and false otherwise. rtcp.cname is left undefined.
-
- - transactionId is left undefined.
- */
-function validateReceiverRtpParameters(param) {
- validateRtpParameters(param);
-
- assert_equals(param.transactionId, undefined,
- 'Expect receiver param.transactionId to be unset');
-
- assert_not_equals(param.rtcp.reducedSize, undefined,
- 'Expect receiver param.rtcp.reducedSize to be set');
-
- assert_equals(param.rtcp.cname, undefined,
- 'Expect receiver param.rtcp.cname to be unset');
-}
-
-/*
- dictionary RTCRtpParameters {
- DOMString transactionId;
- sequence<RTCRtpEncodingParameters> encodings;
- sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
- RTCRtcpParameters rtcp;
- sequence<RTCRtpCodecParameters> codecs;
- };
-
- */
-function validateRtpParameters(param) {
- assert_optional_string_field(param, 'transactionId');
-
- assert_array_field(param, 'headerExtensions');
- for(const headerExt of param.headerExtensions) {
- validateHeaderExtensionParameters(headerExt);
- }
-
- assert_dict_field(param, 'rtcp');
- validateRtcpParameters(param.rtcp);
-
- assert_array_field(param, 'codecs');
- for(const codec of param.codecs) {
- validateCodecParameters(codec);
- }
-}
-
-/*
- dictionary RTCRtpEncodingParameters {
- boolean active;
- unsigned long maxBitrate;
-
- [readonly]
- DOMString rid;
-
- double scaleResolutionDownBy;
- };
-
- */
-function validateEncodingParameters(encoding) {
- assert_optional_boolean_field(encoding, 'active');
- assert_optional_unsigned_int_field(encoding, 'maxBitrate');
-
- assert_optional_string_field(encoding, 'rid');
- assert_optional_number_field(encoding, 'scaleResolutionDownBy');
-}
-
-/*
- dictionary RTCRtcpParameters {
- [readonly]
- DOMString cname;
-
- [readonly]
- boolean reducedSize;
- };
- */
-function validateRtcpParameters(rtcp) {
- assert_optional_string_field(rtcp, 'cname');
- assert_optional_boolean_field(rtcp, 'reducedSize');
-}
-
-/*
- dictionary RTCRtpHeaderExtensionParameters {
- [readonly]
- DOMString uri;
-
- [readonly]
- unsigned short id;
-
- [readonly]
- boolean encrypted;
- };
- */
-function validateHeaderExtensionParameters(headerExt) {
- assert_optional_string_field(headerExt, 'uri');
- assert_optional_unsigned_int_field(headerExt, 'id');
- assert_optional_boolean_field(headerExt, 'encrypted');
-}
-
-/*
- dictionary RTCRtpCodecParameters {
- [readonly]
- unsigned short payloadType;
-
- [readonly]
- DOMString mimeType;
-
- [readonly]
- unsigned long clockRate;
-
- [readonly]
- unsigned short channels;
-
- [readonly]
- DOMString sdpFmtpLine;
- };
- */
-function validateCodecParameters(codec) {
- assert_optional_unsigned_int_field(codec, 'payloadType');
- assert_optional_string_field(codec, 'mimeType');
- assert_optional_unsigned_int_field(codec, 'clockRate');
- assert_optional_unsigned_int_field(codec, 'channels');
- assert_optional_string_field(codec, 'sdpFmtpLine');
-}
-
-// Get the first encoding in param.encodings.
-// Asserts that param.encodings has at least one element.
-function getFirstEncoding(param) {
- const {
- encodings
- } = param;
- assert_equals(encodings.length, 1);
- return encodings[0];
-}
-
-// Helper function to test that modifying an encoding field should succeed
-function test_modified_encoding(kind, field, value1, value2, desc) {
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {
- sender
- } = pc.addTransceiver(kind, {
- sendEncodings: [{
- [field]: value1
- }]
- });
- await doOfferAnswerExchange(t, pc);
-
- const param1 = sender.getParameters();
- validateSenderRtpParameters(param1);
- const encoding1 = getFirstEncoding(param1);
-
- assert_equals(encoding1[field], value1);
- encoding1[field] = value2;
-
- await sender.setParameters(param1);
- const param2 = sender.getParameters();
- validateSenderRtpParameters(param2);
- const encoding2 = getFirstEncoding(param2);
- assert_equals(encoding2[field], value2);
- }, desc + ' with RTCRtpTransceiverInit');
-
- promise_test(async t => {
- const pc = new RTCPeerConnection();
- t.add_cleanup(() => pc.close());
- const {
- sender
- } = pc.addTransceiver(kind);
- await doOfferAnswerExchange(t, pc);
-
- const initParam = sender.getParameters();
- validateSenderRtpParameters(initParam);
- initParam.encodings[0][field] = value1;
- await sender.setParameters(initParam);
-
- const param1 = sender.getParameters();
- validateSenderRtpParameters(param1);
- const encoding1 = getFirstEncoding(param1);
-
- assert_equals(encoding1[field], value1);
- encoding1[field] = value2;
-
- await sender.setParameters(param1);
- const param2 = sender.getParameters();
- validateSenderRtpParameters(param2);
- const encoding2 = getFirstEncoding(param2);
- assert_equals(encoding2[field], value2);
- }, desc + ' without RTCRtpTransceiverInit');
-}
+++ /dev/null
-'use strict';
-
-// Test is based on the following editor draft:
-// webrtc-pc 20171130
-// webrtc-stats 20171122
-
-// This file depends on dictionary-helper.js which should
-// be loaded from the main HTML file.
-
-/*
- [webrtc-stats]
- 6.1. RTCStatsType enum
- enum RTCStatsType {
- "codec",
- "inbound-rtp",
- "outbound-rtp",
- "remote-inbound-rtp",
- "remote-outbound-rtp",
- "csrc",
- "peer-connection",
- "data-channel",
- "stream",
- "track",
- "transport",
- "candidate-pair",
- "local-candidate",
- "remote-candidate",
- "certificate",
- "ice-server"
- };
- */
-const statsValidatorTable = {
- 'codec': validateCodecStats,
- 'inbound-rtp': validateInboundRtpStreamStats,
- 'outbound-rtp': validateOutboundRtpStreamStats,
- 'remote-inbound-rtp': validateRemoteInboundRtpStreamStats,
- 'remote-outbound-rtp': validateRemoteOutboundRtpStreamStats,
- 'media-source': validateMediaSourceStats,
- 'csrc': validateContributingSourceStats,
- 'peer-connection': validatePeerConnectionStats,
- 'data-channel': validateDataChannelStats,
- 'transceiver': validateTransceiverStats,
- 'sender': validateSenderStats,
- 'receiver': validateReceiverStats,
- 'transport': validateTransportStats,
- 'candidate-pair': validateIceCandidatePairStats,
- 'local-candidate': validateIceCandidateStats,
- 'remote-candidate': validateIceCandidateStats,
- 'certificate': validateCertificateStats,
- 'ice-server': validateIceServerStats
-};
-
-// Validate that the stats objects in a stats report
-// follows the respective definitions.
-// Stats objects with unknown type are ignored and
-// only basic validation is done.
-function validateStatsReport(statsReport) {
- for(const [id, stats] of statsReport.entries()) {
- assert_equals(stats.id, id,
- 'expect stats.id to be the same as the key in statsReport');
-
- const validator = statsValidatorTable[stats.type];
- if(validator) {
- validator(statsReport, stats);
- } else {
- validateRtcStats(statsReport, stats);
- }
- }
-}
-
-// Assert that the stats report have stats objects of
-// given types
-function assert_stats_report_has_stats(statsReport, statsTypes) {
- const hasTypes = new Set([...statsReport.values()]
- .map(stats => stats.type));
-
- for(const type of statsTypes) {
- assert_true(hasTypes.has(type),
- `Expect statsReport to contain stats object of type ${type}`);
- }
-}
-
-function findStatsFromReport(statsReport, predicate, message) {
- for (const stats of statsReport.values()) {
- if (predicate(stats)) {
- return stats;
- }
- }
-
- assert_unreached(message || 'none of stats in statsReport satisfy given condition')
-}
-
-// Get stats object of type that is expected to be
-// found in the statsReport
-function getRequiredStats(statsReport, type) {
- for(const stats of statsReport.values()) {
- if(stats.type === type) {
- return stats;
- }
- }
-
- assert_unreached(`required stats of type ${type} is not found in stats report`);
-}
-
-// Get stats object by the stats ID.
-// This is used to retreive other stats objects
-// linked to a stats object
-function getStatsById(statsReport, statsId) {
- assert_true(statsReport.has(statsId),
- `Expect stats report to have stats object with id ${statsId}`);
-
- return statsReport.get(statsId);
-}
-
-// Validate an ID field in a stats object by making sure
-// that the linked stats object is found in the stats report
-// and have the type field value same as expected type
-// It doesn't validate the other fields of the linked stats
-// as validateStatsReport already does all validations
-function validateIdField(statsReport, stats, field, type) {
- assert_string_field(stats, field);
- const linkedStats = getStatsById(statsReport, stats[field]);
- assert_equals(linkedStats.type, type,
- `Expect linked stats object to have type ${type}`);
-}
-
-function validateOptionalIdField(statsReport, stats, field, type) {
- if(stats[field] !== undefined) {
- validateIdField(statsReport, stats, field, type);
- }
-}
-
-/*
- [webrtc-pc]
- 8.4. RTCStats Dictionary
- dictionary RTCStats {
- required DOMHighResTimeStamp timestamp;
- required RTCStatsType type;
- required DOMString id;
- };
- */
-function validateRtcStats(statsReport, stats) {
- assert_number_field(stats, 'timestamp');
- assert_string_field(stats, 'type');
- assert_string_field(stats, 'id');
-}
-
-/*
- [webrtc-stats]
- 7.1. RTCRtpStreamStats dictionary
- dictionary RTCRtpStreamStats : RTCStats {
- unsigned long ssrc;
- DOMString kind;
- DOMString transportId;
- DOMString codecId;
- };
-
- kind of type DOMString
- Either "audio" or "video".
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCRtpStreamStats, with attributes ssrc, kind, transportId, codecId
- */
-function validateRtpStreamStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_unsigned_int_field(stats, 'ssrc');
- assert_string_field(stats, 'kind');
- assert_enum_field(stats, 'kind', ['audio', 'video'])
-
- validateIdField(statsReport, stats, 'transportId', 'transport');
- validateIdField(statsReport, stats, 'codecId', 'codec');
-
-}
-
-/*
- [webrtc-stats]
- 7.2. RTCCodecStats dictionary
- dictionary RTCCodecStats : RTCStats {
- required unsigned long payloadType;
- RTCCodecType codecType;
- required DOMString transportId;
- required DOMString mimeType;
- unsigned long clockRate;
- unsigned long channels;
- DOMString sdpFmtpLine;
- };
-
- enum RTCCodecType {
- "encode",
- "decode",
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCCodecStats, with attributes payloadType, codecType, mimeType, clockRate, channels, sdpFmtpLine
- */
-
-function validateCodecStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_unsigned_int_field(stats, 'payloadType');
- assert_optional_enum_field(stats, 'codecType', ['encode', 'decode']);
-
- validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
-
- assert_string_field(stats, 'mimeType');
- assert_unsigned_int_field(stats, 'clockRate');
- if (stats.kind === 'audio') {
- assert_unsigned_int_field(stats, 'channels');
- }
- assert_string_field(stats, 'sdpFmtpLine');
-}
-
-/*
- [webrtc-stats]
- 7.3. RTCReceivedRtpStreamStats dictionary
- dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats {
- unsigned long long packetsReceived;
- long long packetsLost;
- double jitter;
- unsigned long long packetsDiscarded;
- unsigned long long packetsRepaired;
- unsigned long long burstPacketsLost;
- unsigned long long burstPacketsDiscarded;
- unsigned long burstLossCount;
- unsigned long burstDiscardCount;
- double burstLossRate;
- double burstDiscardRate;
- double gapLossRate;
- double gapDiscardRate;
- unsigned long framesDropped;
- unsigned long partialFramesLost;
- unsigned long fullFramesLost;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCReceivedRtpStreamStats, with all required attributes from its
- inherited dictionaries, and also attributes packetsReceived,
- packetsLost, jitter, packetsDiscarded, framesDropped
- */
-function validateReceivedRtpStreamStats(statsReport, stats) {
- validateRtpStreamStats(statsReport, stats);
-
- assert_unsigned_int_field(stats, 'packetsReceived');
- assert_unsigned_int_field(stats, 'packetsLost');
-
- assert_number_field(stats, 'jitter');
-
- assert_unsigned_int_field(stats, 'packetsDiscarded');
- assert_unsigned_int_field(stats, 'framesDropped');
-
- assert_optional_unsigned_int_field(stats, 'packetsRepaired');
- assert_optional_unsigned_int_field(stats, 'burstPacketsLost');
- assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded');
- assert_optional_unsigned_int_field(stats, 'burstLossCount');
- assert_optional_unsigned_int_field(stats, 'burstDiscardCount');
-
- assert_optional_number_field(stats, 'burstLossRate');
- assert_optional_number_field(stats, 'burstDiscardRate');
- assert_optional_number_field(stats, 'gapLossRate');
- assert_optional_number_field(stats, 'gapDiscardRate');
-
- assert_optional_unsigned_int_field(stats, 'partialFramesLost');
- assert_optional_unsigned_int_field(stats, 'fullFramesLost');
-}
-
-/*
- [webrtc-stats]
- 7.4. RTCInboundRtpStreamStats dictionary
- dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
- DOMString trackId;
- DOMString receiverId;
- DOMString remoteId;
- unsigned long framesDecoded;
- unsigned long keyFramesDecoded;
- unsigned long frameWidth;
- unsigned long frameHeight;
- unsigned long frameBitDepth;
- double framesPerSecond;
- unsigned long long qpSum;
- double totalDecodeTime;
- double totalInterFrameDelay;
- double totalSquaredInterFrameDelay;
- boolean voiceActivityFlag;
- DOMHighResTimeStamp lastPacketReceivedTimestamp;
- double averageRtcpInterval;
- unsigned long long headerBytesReceived;
- unsigned long long fecPacketsReceived;
- unsigned long long fecPacketsDiscarded;
- unsigned long long bytesReceived;
- unsigned long long packetsFailedDecryption;
- unsigned long long packetsDuplicated;
- record<USVString, unsigned long long> perDscpPacketsReceived;
- unsigned long nackCount;
- unsigned long firCount;
- unsigned long pliCount;
- unsigned long sliCount;
- DOMHighResTimeStamp estimatedPlayoutTimestamp;
- double jitterBufferDelay;
- unsigned long long jitterBufferEmittedCount;
- unsigned long long totalSamplesReceived;
- unsigned long long samplesDecodedWithSilk;
- unsigned long long samplesDecodedWithCelt;
- unsigned long long concealedSamples;
- unsigned long long silentConcealedSamples;
- unsigned long long concealmentEvents;
- unsigned long long insertedSamplesForDeceleration;
- unsigned long long removedSamplesForAcceleration;
- double audioLevel;
- double totalAudioEnergy;
- double totalSamplesDuration;
- unsigned long framesReceived;
- DOMString decoderImplementation;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCInboundRtpStreamStats, with all required attributes from its inherited
- dictionaries, and also attributes receiverId, remoteId, framesDecoded, nackCount, framesReceived, bytesReceived, totalAudioEnergy, totalSampleDuration
- */
-function validateInboundRtpStreamStats(statsReport, stats) {
- validateReceivedRtpStreamStats(statsReport, stats);
- validateOptionalIdField(statsReport, stats, 'trackId', 'track');
- validateIdField(statsReport, stats, 'receiverId', 'receiver');
- validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
- assert_unsigned_int_field(stats, 'framesDecoded');
- assert_optional_unsigned_int_field(stats, 'keyFramesDecoded');
- assert_optional_unsigned_int_field(stats, 'frameWidth');
- assert_optional_unsigned_int_field(stats, 'frameHeight');
- assert_optional_unsigned_int_field(stats, 'frameBitDepth');
- assert_optional_number_field(stats, 'framesPerSecond');
- assert_optional_unsigned_int_field(stats, 'qpSum');
- assert_optional_number_field(stats, 'totalDecodeTime');
- assert_optional_number_field(stats, 'totalInterFrameDelay');
- assert_optional_number_field(stats, 'totalSquaredInterFrameDelay');
-
- assert_optional_boolean_field(stats, 'voiceActivityFlag');
-
- assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp');
- assert_optional_number_field(stats, 'averageRtcpInterval');
-
- assert_optional_unsigned_int_field(stats, 'fecPacketsReceived');
- assert_optional_unsigned_int_field(stats, 'fecPacketsDiscarded');
- assert_unsigned_int_field(stats, 'bytesReceived');
- assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
- assert_optional_unsigned_int_field(stats, 'packetsDuplicated');
-
- assert_optional_dict_field(stats, 'perDscpPacketsReceived');
- if (stats['perDscpPacketsReceived']) {
- Object.keys(stats['perDscpPacketsReceived'])
- .forEach(k =>
- assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsReceived to be strings')
- );
- Object.values(stats['perDscpPacketsReceived'])
- .forEach(v =>
- assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsReceived to be strings')
- );
- }
-
- assert_unsigned_int_field(stats, 'nackCount');
-
- assert_optional_unsigned_int_field(stats, 'firCount');
- assert_optional_unsigned_int_field(stats, 'pliCount');
- assert_optional_unsigned_int_field(stats, 'sliCount');
-
- assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
- assert_optional_number_field(stats, 'jitterBufferDelay');
- assert_optional_unsigned_int_field(stats, 'jitterBufferEmittedCount');
- assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
- assert_optional_unsigned_int_field(stats, 'samplesDecodedWithSilk');
- assert_optional_unsigned_int_field(stats, 'samplesDecodedWithCelt');
- assert_optional_unsigned_int_field(stats, 'concealedSamples');
- assert_optional_unsigned_int_field(stats, 'silentConcealedSamples');
- assert_optional_unsigned_int_field(stats, 'concealmentEvents');
- assert_optional_unsigned_int_field(stats, 'insertedSamplesForDeceleration');
- assert_optional_unsigned_int_field(stats, 'removedSamplesForAcceleration');
- assert_optional_number_field(stats, 'audioLevel');
- assert_optional_number_field(stats, 'totalAudioEnergy');
- assert_optional_number_field(stats, 'totalSamplesDuration');
- assert_unsigned_int_field(stats, 'framesReceived');
- assert_optional_string_field(stats, 'decoderImplementation');
-}
-
-/*
- [webrtc-stats]
- 7.5. RTCRemoteInboundRtpStreamStats dictionary
- dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
- DOMString localId;
- double roundTripTime;
- double totalRoundTripTime;
- double fractionLost;
- unsigned long long reportsReceived;
- unsigned long long roundTripTimeMeasurements;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCRemoteInboundRtpStreamStats, with all required attributes from its
- inherited dictionaries, and also attributes localId, roundTripTime
- */
-function validateRemoteInboundRtpStreamStats(statsReport, stats) {
- validateReceivedRtpStreamStats(statsReport, stats);
-
- validateIdField(statsReport, stats, 'localId', 'outbound-rtp');
- assert_number_field(stats, 'roundTripTime');
- assert_optional_number_field(stats, 'totalRoundTripTime');
- assert_optional_number_field(stats, 'fractionLost');
- assert_optional_unsigned_int_field(stats, 'reportsReceived');
- assert_optional_unsigned_int_field(stats, 'roundTripTimeMeasurements');
-}
-
-/*
- [webrtc-stats]
- 7.6. RTCSentRtpStreamStats dictionary
- dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
- unsigned long packetsSent;
- unsigned long long bytesSent;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCSentRtpStreamStats, with all required attributes from its inherited
- dictionaries, and also attributes packetsSent, bytesSent
- */
-function validateSentRtpStreamStats(statsReport, stats) {
- validateRtpStreamStats(statsReport, stats);
-
- assert_unsigned_int_field(stats, 'packetsSent');
- assert_unsigned_int_field(stats, 'bytesSent');
-}
-
-/*
- [webrtc-stats]
- 7.7. RTCOutboundRtpStreamStats dictionary
- dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
- DOMString mediaSourceId;
- DOMString senderId;
- DOMString remoteId;
- DOMString rid;
- DOMHighResTimeStamp lastPacketSentTimestamp;
- unsigned long long headerBytesSent;
- unsigned long packetsDiscardedOnSend;
- unsigned long long bytesDiscardedOnSend;
- unsigned long fecPacketsSent;
- unsigned long long retransmittedPacketsSent;
- unsigned long long retransmittedBytesSent;
- double targetBitrate;
- unsigned long long totalEncodedBytesTarget;
- unsigned long frameWidth;
- unsigned long frameHeight;
- unsigned long frameBitDepth;
- double framesPerSecond;
- unsigned long framesSent;
- unsigned long hugeFramesSent;
- unsigned long framesEncoded;
- unsigned long keyFramesEncoded;
- unsigned long framesDiscardedOnSend;
- unsigned long long qpSum;
- unsigned long long totalSamplesSent;
- unsigned long long samplesEncodedWithSilk;
- unsigned long long samplesEncodedWithCelt;
- boolean voiceActivityFlag;
- double totalEncodeTime;
- double totalPacketSendDelay;
- double averageRtcpInterval;
- RTCQualityLimitationReason qualityLimitationReason;
- record<DOMString, double> qualityLimitationDurations;
- unsigned long qualityLimitationResolutionChanges;
- record<USVString, unsigned long long> perDscpPacketsSent;
- unsigned long nackCount;
- unsigned long firCount;
- unsigned long pliCount;
- unsigned long sliCount;
- DOMString encoderImplementation;
- };
- Obsolete members:
- partial dictionary RTCOutboundStreamStats {
- DOMString trackId;
- };
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCOutboundRtpStreamStats, with all required attributes from its
- inherited dictionaries, and also attributes senderId, remoteId, framesEncoded, nackCount, framesSent
- */
-function validateOutboundRtpStreamStats(statsReport, stats) {
- validateSentRtpStreamStats(statsReport, stats)
-
- validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
- validateIdField(statsReport, stats, 'senderId', 'sender');
- validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
-
- assert_optional_string_field(stats, 'rid');
-
- assert_optional_number_field(stats, 'lastPacketSentTimestamp');
- assert_optional_unsigned_int_field(stats, 'headerBytesSent');
- assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
- assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
- assert_optional_unsigned_int_field(stats, 'fecPacketsSent');
- assert_optional_unsigned_int_field(stats, 'retransmittedPacketsSent');
- assert_optional_unsigned_int_field(stats, 'retransmittedBytesSent');
- assert_optional_number_field(stats, 'targetBitrate');
- assert_optional_unsigned_int_field(stats, 'totalEncodedBytesTarget');
- if (stats['kind'] === 'video') {
- assert_optional_unsigned_int_field(stats, 'frameWidth');
- assert_optional_unsigned_int_field(stats, 'frameHeight');
- assert_optional_unsigned_int_field(stats, 'frameBitDepth');
- assert_optional_number_field(stats, 'framesPerSecond');
- assert_unsigned_int_field(stats, 'framesSent');
- assert_optional_unsigned_int_field(stats, 'hugeFramesSent');
- assert_unsigned_int_field(stats, 'framesEncoded');
- assert_optional_unsigned_int_field(stats, 'keyFramesEncoded');
- assert_optional_unsigned_int_field(stats, 'framesDiscardedOnSend');
- assert_optional_unsigned_int_field(stats, 'qpSum');
- } else if (stats['kind'] === 'audio') {
- assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
- assert_optional_unsigned_int_field(stats, 'samplesEncodedWithSilk');
- assert_optional_unsigned_int_field(stats, 'samplesEncodedWithCelt');
- assert_optional_boolean_field(stats, 'voiceActivityFlag');
- }
- assert_optional_number_field(stats, 'totalEncodeTime');
- assert_optional_number_field(stats, 'totalPacketSendDelay');
- assert_optional_number_field(stats, 'averageRTCPInterval');
-
- if (stats['kind'] === 'video') {
- assert_optional_enum_field(stats, 'qualityLimitationReason', ['none', 'cpu', 'bandwidth', 'other']);
-
- assert_optional_dict_field(stats, 'qualityLimitationDurations');
- if (stats['qualityLimitationDurations']) {
- Object.keys(stats['qualityLimitationDurations'])
- .forEach(k =>
- assert_equals(typeof k, 'string', 'Expect keys of qualityLimitationDurations to be strings')
- );
- Object.values(stats['qualityLimitationDurations'])
- .forEach(v =>
- assert_equals(typeof num, 'number', 'Expect values of qualityLimitationDurations to be numbers')
- );
- }
-
- assert_optional_unsigned_int_field(stats, 'qualityLimitationResolutionChanges');
- }
- assert_unsigned_int_field(stats, 'nackCount');
- assert_optional_dict_field(stats, 'perDscpPacketsSent');
- if (stats['perDscpPacketsSent']) {
- Object.keys(stats['perDscpPacketsSent'])
- .forEach(k =>
- assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsSent to be strings')
- );
- Object.values(stats['perDscpPacketsSent'])
- .forEach(v =>
- assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsSent to be strings')
- );
- }
-
- assert_optional_unsigned_int_field(stats, 'firCount');
- assert_optional_unsigned_int_field(stats, 'pliCount');
- assert_optional_unsigned_int_field(stats, 'sliCount');
- assert_optional_string_field(stats, 'encoderImplementation');
- // Obsolete stats
- validateOptionalIdField(statsReport, stats, 'trackId', 'track');
-}
-
-/*
- [webrtc-stats]
- 7.8. RTCRemoteOutboundRtpStreamStats dictionary
- dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {
- DOMString localId;
- DOMHighResTimeStamp remoteTimestamp;
- unsigned long long reportsSent;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCRemoteOutboundRtpStreamStats, with all required attributes from its
- inherited dictionaries, and also attributes localId, remoteTimestamp
- */
-function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
- validateSentRtpStreamStats(statsReport, stats);
-
- validateIdField(statsReport, stats, 'localId', 'inbound-rtp');
- assert_number_field(stats, 'remoteTimeStamp');
- assert_optional_unsigned_int_field(stats, 'reportsSent');
-}
-
-/*
- [webrtc-stats]
- 7.11 RTCMediaSourceStats dictionary
- dictionary RTCMediaSourceStats : RTCStats {
- DOMString trackIdentifier;
- DOMString kind;
- };
-
- dictionary RTCAudioSourceStats : RTCMediaSourceStats {
- double audioLevel;
- double totalAudioEnergy;
- double totalSamplesDuration;
- double echoReturnLoss;
- double echoReturnLossEnhancement;
- };
-
- dictionary RTCVideoSourceStats : RTCMediaSourceStats {
- unsigned long width;
- unsigned long height;
- unsigned long bitDepth;
- unsigned long frames;
- // see https://github.com/w3c/webrtc-stats/issues/540
- double framesPerSecond;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- RTCMediaSourceStats with attributes trackIdentifier, kind
- RTCAudioSourceStats, with all required attributes from its inherited dictionaries and totalAudioEnergy, totalSamplesDuration
- RTCVideoSourceStats, with all required attributes from its inherited dictionaries and width, height, framesPerSecond
-*/
-function validateMediaSourceStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
- assert_string_field(stats, 'trackIdentifier');
- assert_enum_field(stats, 'kind', ['audio', 'video']);
-
- if (stats.kind === 'audio') {
- assert_optional_number_field(stats, 'audioLevel');
- assert_number_field(stats, 'totalAudioEnergy');
- assert_number_field(stats, 'totalSamplesDuration');
- assert_optional_number_field(stats, 'echoReturnLoss');
- assert_optional_number_field(stats, 'echoReturnLossEnhancement');
- } else if (stats.kind === 'video') {
- assert_unsigned_int_field(stats, 'width');
- assert_unsigned_int_field(stats, 'height');
- assert_optional_unsigned_int_field(stats, 'bitDpeth');
- assert_optional_unsigned_int_field(stats, 'frames');
- assert_number_field(stats, 'framesPerSecond');
- }
-}
-
-/*
- [webrtc-stats]
- 7.9. RTCRTPContributingSourceStats
- dictionary RTCRTPContributingSourceStats : RTCStats {
- unsigned long contributorSsrc;
- DOMString inboundRtpStreamId;
- unsigned long packetsContributedTo;
- double audioLevel;
- };
- */
-function validateContributingSourceStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_optional_unsigned_int_field(stats, 'contributorSsrc');
-
- validateOptionalIdField(statsReport, stats, 'inboundRtpStreamId', 'inbound-rtp');
- assert_optional_unsigned_int_field(stats, 'packetsContributedTo');
- assert_optional_number_field(stats, 'audioLevel');
-}
-
-/*
- [webrtc-stats]
- 7.10. RTCPeerConnectionStats dictionary
- dictionary RTCPeerConnectionStats : RTCStats {
- unsigned long dataChannelsOpened;
- unsigned long dataChannelsClosed;
- unsigned long dataChannelsRequested;
- unsigned long dataChannelsAccepted;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCPeerConnectionStats, with attributes dataChannelsOpened, dataChannelsClosed
- */
-function validatePeerConnectionStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_unsigned_int_field(stats, 'dataChannelsOpened');
- assert_unsigned_int_field(stats, 'dataChannelsClosed');
- assert_optional_unsigned_int_field(stats, 'dataChannelsRequested');
- assert_optional_unsigned_int_field(stats, 'dataChannelsAccepted');
-}
-
-/* [webrtc-stats]
- 7.16 RTCRtpTransceiverStats dictionary
- dictionary RTCRtpTransceiverStats {
- DOMString senderId;
- DOMString receiverId;
- DOMString mid;
- };
-*/
-function validateTransceiverStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
- validateOptionalIdField(statsReport, stats, 'senderId', 'sender');
- validateOptionalIdField(statsReport, stats, 'receiverId', 'sender');
- assert_optional_string_field(stats, 'mid');
-}
-
-/*
- [webrtc-stats]
- dictionary RTCMediaHandlerStats : RTCStats {
- DOMString trackIdentifier;
- boolean remoteSource;
- boolean ended;
- DOMString kind;
- RTCPriorityType priority;
- };
- dictionary RTCVideoHandlerStats : RTCMediaHandlerStats {
- };
- dictionary RTCAudioHandlerStats : RTCMediaHandlerStats {
- };
- Used from validateSenderStats and validateReceiverStats
-
- [webrtc-priority]
- enum RTCPriorityType {
- "very-low",
- "low",
- "medium",
- "high"
- };
-
- [webrtc-pc]
- MTI:
- RTCMediaHandlerStats with attributes trackIdentifier
- RTCAudioHandlerStats, with all required attributes from its inherited dictionaries
- RTCVideoHandlerStats, with all required attributes from its inherited dictionaries
-
-*/
-function validateMediaHandlerStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
- assert_string_field(stats, 'trackIdentifier');
- assert_optional_boolean_field(stats, 'remoteSource');
- assert_optional_boolean_field(stats, 'ended');
- assert_optional_string_field(stats, 'kind');
- assert_enum_field(stats, 'priority', ['very-low', 'low', 'medium', 'high']);
-}
-
-/*
- [webrtc-stats]
- dictionary RTCAudioSenderStats : RTCAudioHandlerStats {
- DOMString mediaSourceId;
- };
- dictionary RTCVideoSenderStats : RTCVideoHandlerStats {
- DOMString mediaSourceId;
- };
-
- [webrtc-pc]
- MTI:
- RTCVideoSenderStats, with all required attributes from its inherited dictionaries
-*/
-function validateSenderStats(statsReport, stats) {
- validateMediaHandlerStats(statsReport, stats);
- validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
-}
-
-/*
- [webrtc-stats]
- dictionary RTCAudioReceiverStats : RTCAudioHandlerStats {
- };
- dictionary RTCVideoReceiverStats : RTCVideoHandlerStats {
- };
-
- [webrtc-pc]
- MTI:
- RTCVideoReceiverStats, with all required attributes from its inherited dictionaries
-*/
-function validateReceiverStats(statsReport, stats) {
- validateMediaHandlerStats(statsReport, stats);
-}
-
-
-/*
- [webrtc-stats]
- 7.13. RTCDataChannelStats dictionary
- dictionary RTCDataChannelStats : RTCStats {
- DOMString label;
- DOMString protocol;
- // see https://github.com/w3c/webrtc-stats/issues/541
- unsigned short dataChannelIdentifier;
- DOMString transportId;
- RTCDataChannelState state;
- unsigned long messagesSent;
- unsigned long long bytesSent;
- unsigned long messagesReceived;
- unsigned long long bytesReceived;
- };
-
- [webrtc-pc]
- 6.2. RTCDataChannel
- enum RTCDataChannelState {
- "connecting",
- "open",
- "closing",
- "closed"
- };
-
- 8.6. Mandatory To Implement Stats
- - RTCDataChannelStats, with attributes label, protocol, datachannelIdentifier, state,
- messagesSent, bytesSent, messagesReceived, bytesReceived
- */
-function validateDataChannelStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_string_field(stats, 'label');
- assert_string_field(stats, 'protocol');
- assert_unsigned_int_field(stats, 'dataChannelIdentifier');
-
- validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
-
- assert_enum_field(stats, 'state',
- ['connecting', 'open', 'closing', 'closed']);
-
- assert_unsigned_int_field(stats, 'messagesSent');
- assert_unsigned_int_field(stats, 'bytesSent');
- assert_unsigned_int_field(stats, 'messagesReceived');
- assert_unsigned_int_field(stats, 'bytesReceived');
-}
-
-/*
- [webrtc-stats]
- 7.14. RTCTransportStats dictionary
- dictionary RTCTransportStats : RTCStats {
- unsigned long long packetsSent;
- unsigned long long packetsReceived;
- unsigned long long bytesSent;
- unsigned long long bytesReceived;
- DOMString rtcpTransportStatsId;
- RTCIceRole iceRole;
- RTCDtlsTransportState dtlsState;
- DOMString selectedCandidatePairId;
- DOMString localCertificateId;
- DOMString remoteCertificateId;
- DOMString tlsVersion;
- DOMString dtlsCipher;
- DOMString srtpCipher;
- DOMString tlsGroup;
- unsigned long selectedCandidatePairChanges;
- };
-
- [webrtc-pc]
- 5.5. RTCDtlsTransportState Enum
- enum RTCDtlsTransportState {
- "new",
- "connecting",
- "connected",
- "closed",
- "failed"
- };
-
- 5.6. RTCIceRole Enum
- enum RTCIceRole {
- "unknown",
- "controlling",
- "controlled"
- };
-
- 8.6. Mandatory To Implement Stats
- - RTCTransportStats, with attributes bytesSent, bytesReceived,
- selectedCandidatePairId, localCertificateId,
- remoteCertificateId
- */
-function validateTransportStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_optional_unsigned_int_field(stats, 'packetsSent');
- assert_optional_unsigned_int_field(stats, 'packetsReceived');
- assert_unsigned_int_field(stats, 'bytesSent');
- assert_unsigned_int_field(stats, 'bytesReceived');
-
- validateOptionalIdField(statsReport, stats, 'rtcpTransportStatsId',
- 'transport');
-
- assert_optional_enum_field(stats, 'iceRole',
- ['unknown', 'controlling', 'controlled']);
-
- assert_optional_enum_field(stats, 'dtlsState',
- ['new', 'connecting', 'connected', 'closed', 'failed']);
-
- validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair');
- validateIdField(statsReport, stats, 'localCertificateId', 'certificate');
- validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate');
- assert_optional_string_field(stats, 'tlsVersion');
- assert_optional_string_field(stats, 'dtlsCipher');
- assert_optional_string_field(stats, 'srtpCipher');
- assert_optional_string_field(stats, 'tlsGroup');
- assert_optional_unsigned_int_field(stats, 'selectedCandidatePairChanges');
-}
-
-/*
- [webrtc-stats]
- 7.15. RTCIceCandidateStats dictionary
- dictionary RTCIceCandidateStats : RTCStats {
- required DOMString transportId;
- DOMString? address;
- long port;
- DOMString protocol;
- RTCIceCandidateType candidateType;
- long priority;
- DOMString url;
- DOMString relayProtocol;
- };
-
- [webrtc-pc]
- 4.8.1.3. RTCIceCandidateType Enum
- enum RTCIceCandidateType {
- "host",
- "srflx",
- "prflx",
- "relay"
- };
-
- 8.6. Mandatory To Implement Stats
- - RTCIceCandidateStats, with attributes address, port, protocol, candidateType, url
- */
-function validateIceCandidateStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- validateIdField(statsReport, stats, 'transportId', 'transport');
- // The address is mandatory to implement, but is allowed to be null
- // when hidden for privacy reasons.
- if (stats.address != null) {
- // Departure from strict spec reading:
- // This field is populated in a racy manner in Chrome.
- // We allow it to be present or not present for the time being.
- // TODO(https://bugs.chromium.org/1092721): Become consistent.
- assert_optional_string_field(stats, 'address');
- }
- assert_unsigned_int_field(stats, 'port');
- assert_string_field(stats, 'protocol');
-
- assert_enum_field(stats, 'candidateType',
- ['host', 'srflx', 'prflx', 'relay']);
-
- assert_optional_int_field(stats, 'priority');
- // The url field is mandatory for local candidates gathered from
- // a STUN or TURN server, and MUST NOT be present otherwise.
- // TODO(hta): Improve checking.
- assert_optional_string_field(stats, 'url');
- assert_optional_string_field(stats, 'relayProtocol');
-}
-
-/*
- [webrtc-stats]
- 7.16. RTCIceCandidatePairStats dictionary
- dictionary RTCIceCandidatePairStats : RTCStats {
- DOMString transportId;
- DOMString localCandidateId;
- DOMString remoteCandidateId;
- RTCStatsIceCandidatePairState state;
- boolean nominated;
- unsigned long packetsSent;
- unsigned long packetsReceived;
- unsigned long long bytesSent;
- unsigned long long bytesReceived;
- DOMHighResTimeStamp lastPacketSentTimestamp;
- DOMHighResTimeStamp lastPacketReceivedTimestamp;
- DOMHighResTimeStamp firstRequestTimestamp;
- DOMHighResTimeStamp lastRequestTimestamp;
- DOMHighResTimeStamp lastResponseTimestamp;
- double totalRoundTripTime;
- double currentRoundTripTime;
- double availableOutgoingBitrate;
- double availableIncomingBitrate;
- unsigned long circuitBreakerTriggerCount;
- unsigned long long requestsReceived;
- unsigned long long requestsSent;
- unsigned long long responsesReceived;
- unsigned long long responsesSent;
- unsigned long long retransmissionsReceived;
- unsigned long long retransmissionsSent;
- unsigned long long consentRequestsSent;
- DOMHighResTimeStamp consentExpiredTimestamp;
- unsigned long packetsDiscardedOnSend;
- unsigned long long bytesDiscardedOnSend; };
-
- enum RTCStatsIceCandidatePairState {
- "frozen",
- "waiting",
- "in-progress",
- "failed",
- "succeeded"
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCIceCandidatePairStats, with attributes transportId, localCandidateId,
- remoteCandidateId, state, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
- // not including priority per https://github.com/w3c/webrtc-pc/issues/2457
- */
-function validateIceCandidatePairStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- validateIdField(statsReport, stats, 'transportId', 'transport');
- validateIdField(statsReport, stats, 'localCandidateId', 'local-candidate');
- validateIdField(statsReport, stats, 'remoteCandidateId', 'remote-candidate');
-
- assert_enum_field(stats, 'state',
- ['frozen', 'waiting', 'in-progress', 'failed', 'succeeded']);
-
- assert_boolean_field(stats, 'nominated');
- assert_optional_unsigned_int_field(stats, 'packetsSent');
- assert_optional_unsigned_int_field(stats, 'packetsReceived');
- assert_unsigned_int_field(stats, 'bytesSent');
- assert_unsigned_int_field(stats, 'bytesReceived');
-
- assert_optional_number_field(stats, 'lastPacketSentTimestamp');
- assert_optional_number_field(stats, 'lastPacketReceivedTimestamp');
- assert_optional_number_field(stats, 'firstRequestTimestamp');
- assert_optional_number_field(stats, 'lastRequestTimestamp');
- assert_optional_number_field(stats, 'lastResponseTimestamp');
-
- assert_number_field(stats, 'totalRoundTripTime');
- assert_number_field(stats, 'currentRoundTripTime');
-
- assert_optional_number_field(stats, 'availableOutgoingBitrate');
- assert_optional_number_field(stats, 'availableIncomingBitrate');
-
- assert_optional_unsigned_int_field(stats, 'circuitBreakerTriggerCount');
- assert_optional_unsigned_int_field(stats, 'requestsReceived');
- assert_optional_unsigned_int_field(stats, 'requestsSent');
- assert_optional_unsigned_int_field(stats, 'responsesReceived');
- assert_optional_unsigned_int_field(stats, 'responsesSent');
- assert_optional_unsigned_int_field(stats, 'retransmissionsReceived');
- assert_optional_unsigned_int_field(stats, 'retransmissionsSent');
- assert_optional_unsigned_int_field(stats, 'consentRequestsSent');
- assert_optional_number_field(stats, 'consentExpiredTimestamp');
- assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
- assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
-}
-
-/*
- [webrtc-stats]
- 7.17. RTCCertificateStats dictionary
- dictionary RTCCertificateStats : RTCStats {
- DOMString fingerprint;
- DOMString fingerprintAlgorithm;
- DOMString base64Certificate;
- DOMString issuerCertificateId;
- };
-
- [webrtc-pc]
- 8.6. Mandatory To Implement Stats
- - RTCCertificateStats, with attributes fingerprint, fingerprintAlgorithm,
- base64Certificate, issuerCertificateId
- */
-function validateCertificateStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_string_field(stats, 'fingerprint');
- assert_string_field(stats, 'fingerprintAlgorithm');
- assert_string_field(stats, 'base64Certificate');
- assert_optional_string_field(stats, 'issuerCertificateId');
-}
-
-/*
- [webrtc-stats]
- 7.30. RTCIceServerStats dictionary
- dictionary RTCIceServerStats : RTCStats {
- DOMString url;
- long port;
- DOMString protocol;
- unsigned long totalRequestsSent;
- unsigned long totalResponsesReceived;
- double totalRoundTripTime;
- };
-*/
-function validateIceServerStats(statsReport, stats) {
- validateRtcStats(statsReport, stats);
-
- assert_optional_string_field(stats, 'url');
- assert_optional_int_field(stats, 'port');
- assert_optional_string_field(stats, 'protocol');
- assert_optional_unsigned_int_field(stats, 'totalRequestsSent');
- assert_optional_unsigned_int_field(stats, 'totalResponsesReceived');
- assert_optional_number_field(stats, 'totalRoundTripTime');
-}
+++ /dev/null
-'use strict';
-
-// Helper assertion functions to validate dictionary fields
-// on dictionary objects returned from APIs
-
-function assert_unsigned_int_field(object, field) {
- const num = object[field];
- assert_true(Number.isInteger(num) && (num >= 0),
- `Expect dictionary.${field} to be unsigned integer`);
-}
-
-function assert_int_field(object, field) {
- const num = object[field];
- assert_true(Number.isInteger(num),
- `Expect dictionary.${field} to be integer`);
-}
-
-function assert_string_field(object, field) {
- const str = object[field];
- assert_equals(typeof str, 'string',
- `Expect dictionary.${field} to be string`);
-}
-
-function assert_number_field(object, field) {
- const num = object[field];
- assert_equals(typeof num, 'number',
- `Expect dictionary.${field} to be number`);
-}
-
-function assert_boolean_field(object, field) {
- const bool = object[field];
- assert_equals(typeof bool, 'boolean',
- `Expect dictionary.${field} to be boolean`);
-}
-
-function assert_array_field(object, field) {
- assert_true(Array.isArray(object[field]),
- `Expect dictionary.${field} to be array`);
-}
-
-function assert_dict_field(object, field) {
- assert_equals(typeof object[field], 'object',
- `Expect dictionary.${field} to be plain object`);
-
- assert_not_equals(object[field], null,
- `Expect dictionary.${field} to not be null`);
-}
-
-function assert_enum_field(object, field, validValues) {
- assert_string_field(object, field);
- assert_true(validValues.includes(object[field]),
- `Expect dictionary.${field} to have one of the valid enum values: ${validValues}`);
-}
-
-function assert_optional_unsigned_int_field(object, field) {
- if(object[field] !== undefined) {
- assert_unsigned_int_field(object, field);
- }
-}
-
-function assert_optional_int_field(object, field) {
- if(object[field] !== undefined) {
- assert_int_field(object, field);
- }
-}
-
-function assert_optional_string_field(object, field) {
- if(object[field] !== undefined) {
- assert_string_field(object, field);
- }
-}
-
-function assert_optional_number_field(object, field) {
- if(object[field] !== undefined) {
- assert_number_field(object, field);
- }
-}
-
-function assert_optional_boolean_field(object, field) {
- if(object[field] !== undefined) {
- assert_boolean_field(object, field);
- }
-}
-
-function assert_optional_array_field(object, field) {
- if(object[field] !== undefined) {
- assert_array_field(object, field);
- }
-}
-
-function assert_optional_dict_field(object, field) {
- if(object[field] !== undefined) {
- assert_dict_field(object, field);
- }
-}
-
-function assert_optional_enum_field(object, field, validValues) {
- if(object[field] !== undefined) {
- assert_enum_field(object, field, validValues);
- }
-}
+++ /dev/null
-/**
- * Host information for cross-origin tests.
- * @returns {Object} with properties for different host information.
- */
-function get_host_info() {
-
- var HTTP_PORT = '8000';
- var HTTP_PORT2 = '81';
- var HTTPS_PORT = '443';
- var HTTPS_PORT2 = '444';
- var PROTOCOL = self.location.protocol;
- var IS_HTTPS = (PROTOCOL == "https:");
- var PORT = IS_HTTPS ? HTTPS_PORT : HTTP_PORT;
- var PORT2 = IS_HTTPS ? HTTPS_PORT2 : HTTP_PORT2;
- var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT);
- var HTTP_PORT2_ELIDED = HTTP_PORT2 == "80" ? "" : (":" + HTTP_PORT2);
- var HTTPS_PORT_ELIDED = HTTPS_PORT == "443" ? "" : (":" + HTTPS_PORT);
- var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED;
- var ORIGINAL_HOST = 'w3c-test.org';
- var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www.' + ORIGINAL_HOST);
- var OTHER_HOST = 'www2.w3c-test.org';
- var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('not-web-platform.test');
-
- return {
- HTTP_PORT: HTTP_PORT,
- HTTP_PORT2: HTTP_PORT2,
- HTTPS_PORT: HTTPS_PORT,
- HTTPS_PORT2: HTTPS_PORT2,
- PORT: PORT,
- PORT2: PORT2,
- ORIGINAL_HOST: ORIGINAL_HOST,
- REMOTE_HOST: REMOTE_HOST,
-
- ORIGIN: PROTOCOL + "//" + ORIGINAL_HOST + PORT_ELIDED,
- HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + HTTP_PORT_ELIDED,
- HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
- HTTPS_ORIGIN_WITH_CREDS: 'https://foo:bar@' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
- HTTP_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + ORIGINAL_HOST + HTTP_PORT2_ELIDED,
- REMOTE_ORIGIN: PROTOCOL + "//" + REMOTE_HOST + PORT_ELIDED,
- OTHER_ORIGIN: PROTOCOL + "//" + OTHER_HOST + PORT_ELIDED,
- HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + HTTP_PORT_ELIDED,
- HTTP_NOTSAMESITE_ORIGIN: 'http://' + NOTSAMESITE_HOST + HTTP_PORT_ELIDED,
- HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + REMOTE_HOST + HTTP_PORT2_ELIDED,
- HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
- HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
- HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
- UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
- AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
- };
-}
-
-/**
- * When a default port is used, location.port returns the empty string.
- * This function attempts to provide an exact port, assuming we are running under wptserve.
- * @param {*} loc - can be Location/<a>/<area>/URL, but assumes http/https only.
- * @returns {string} The port number.
- */
-function get_port(loc) {
- if (loc.port) {
- return loc.port;
- }
- return loc.protocol === 'https:' ? '443' : '80';
-}
+++ /dev/null
-// META: script=/resources/WebIDLParser.js
-// META: script=/resources/idlharness.js
-// META: script=./RTCPeerConnection-helper.js
-// META: timeout=long
-
-'use strict';
-
-// The following helper functions are called from RTCPeerConnection-helper.js:
-// generateAnswer()
-// getNoiseStream()
-
-// Put the global IDL test objects under a parent object.
-// This allows easier search for the test cases when
-// viewing the web page
-const idlTestObjects = {};
-
-// Helper function to create RTCTrackEvent object
-function initTrackEvent() {
- const pc = new RTCPeerConnection();
- const transceiver = pc.addTransceiver('audio');
- const { sender, receiver } = transceiver;
- const { track } = receiver;
- return new RTCTrackEvent('track', {
- receiver, track, transceiver
- });
-}
-
-// List of async test driver functions
-const asyncInitTasks = [
- asyncInitCertificate,
- asyncInitTransports,
- asyncInitMediaStreamTrack,
-];
-
-// Asynchronously generate an RTCCertificate
-function asyncInitCertificate() {
- return RTCPeerConnection.generateCertificate({
- name: 'RSASSA-PKCS1-v1_5',
- modulusLength: 2048,
- publicExponent: new Uint8Array([1, 0, 1]),
- hash: 'SHA-256'
- }).then(cert => {
- idlTestObjects.certificate = cert;
- });
-}
-
-// Asynchronously generate instances of
-// RTCSctpTransport, RTCDtlsTransport,
-// and RTCIceTransport
-function asyncInitTransports() {
- const pc = new RTCPeerConnection();
- pc.createDataChannel('test');
-
- // setting answer description initializes pc.sctp
- return pc.createOffer()
- .then(offer =>
- pc.setLocalDescription(offer)
- .then(() => generateAnswer(offer)))
- .then(answer => pc.setRemoteDescription(answer))
- .then(() => {
- const sctpTransport = pc.sctp;
- assert_true(sctpTransport instanceof RTCSctpTransport,
- 'Expect pc.sctp to be instance of RTCSctpTransport');
- idlTestObjects.sctpTransport = sctpTransport;
-
- const dtlsTransport = sctpTransport.transport;
- assert_true(dtlsTransport instanceof RTCDtlsTransport,
- 'Expect sctpTransport.transport to be instance of RTCDtlsTransport');
- idlTestObjects.dtlsTransport = dtlsTransport;
-
- const iceTransport = dtlsTransport.iceTransport;
- assert_true(iceTransport instanceof RTCIceTransport,
- 'Expect sctpTransport.transport to be instance of RTCDtlsTransport');
- idlTestObjects.iceTransport = iceTransport;
- });
-}
-
-// Asynchoronously generate MediaStreamTrack from getUserMedia
-function asyncInitMediaStreamTrack() {
- return getNoiseStream({ audio: true })
- .then(mediaStream => {
- idlTestObjects.mediaStreamTrack = mediaStream.getTracks()[0];
- });
-}
-
-// Run all async test drivers, report and swallow any error
-// thrown/rejected. Proper test for correct initialization
-// of the objects are done in their respective test files.
-function asyncInit() {
- return Promise.all(asyncInitTasks.map(
- task => {
- const t = async_test(`Test driver for ${task.name}`);
- let promise;
- t.step(() => {
- promise = task().then(
- t.step_func_done(),
- t.step_func(err =>
- assert_unreached(`Failed to run ${task.name}: ${err}`)));
- });
- return promise;
- }));
-}
-
-idl_test(
- ['webrtc'],
- ['webidl', 'mediacapture-streams', 'hr-time', 'dom', 'html'],
- async idlArray => {
- idlArray.add_objects({
- RTCPeerConnection: [`new RTCPeerConnection()`],
- RTCSessionDescription: [`new RTCSessionDescription({ type: 'offer' })`],
- RTCIceCandidate: [`new RTCIceCandidate({ sdpMid: 1 })`],
- RTCDataChannel: [`new RTCPeerConnection().createDataChannel('')`],
- RTCRtpTransceiver: [`new RTCPeerConnection().addTransceiver('audio')`],
- RTCRtpSender: [`new RTCPeerConnection().addTransceiver('audio').sender`],
- RTCRtpReceiver: [`new RTCPeerConnection().addTransceiver('audio').receiver`],
- RTCPeerConnectionIceEvent: [`new RTCPeerConnectionIceEvent('ice')`],
- RTCPeerConnectionIceErrorEvent: [
- `new RTCPeerConnectionIceErrorEvent('ice-error', { port: 0, errorCode: 701 });`
- ],
- RTCTrackEvent: [`initTrackEvent()`],
- RTCErrorEvent: [`new RTCErrorEvent('error')`],
- RTCDataChannelEvent: [
- `new RTCDataChannelEvent('channel', {
- channel: new RTCPeerConnection().createDataChannel('')
- })`
- ],
- // Async initialized objects below
- RTCCertificate: ['idlTestObjects.certificate'],
- RTCSctpTransport: ['idlTestObjects.sctpTransport'],
- RTCDtlsTransport: ['idlTestObjects.dtlsTransport'],
- RTCIceTransport: ['idlTestObjects.iceTransport'],
- MediaStreamTrack: ['idlTestObjects.mediaStreamTrack'],
- });
- /*
- TODO
- RTCRtpContributingSource
- RTCRtpSynchronizationSource
- RTCDTMFSender
- RTCDTMFToneChangeEvent
- RTCIdentityProviderRegistrar
- RTCIdentityAssertion
- */
-
- await asyncInit();
- }
-);
+++ /dev/null
-// Set permissions for camera and microphone using Web Driver
-// Status can be one of "granted" or "denied"
-// Scope take values from permission names
-async function setMediaPermission(status="granted", scope=["camera", "microphone"]) {
- try {
- for (let s of scope) {
- await test_driver.set_permission({ name: s }, status, true);
- }
- } catch (e) {
- const noSetPermissionSupport = typeof e === "string" && e.match(/set_permission not implemented/);
- if (!(noSetPermissionSupport ||
- (e instanceof Error && e.message.match("unimplemented")) )) {
- throw e;
- }
- // Web Driver not implemented action
- // FF: https://bugzilla.mozilla.org/show_bug.cgi?id=1524074
-
- // with current WPT runners, will default to granted state for FF and Safari
- // throw if status!="granted" to invalidate test results
- if (status === "denied") {
- assert_implements_optional(!noSetPermissionSupport, "Unable to set permission to denied for this test");
- }
- }
-}
+++ /dev/null
-## sdp
-Third-party SDP module from
- https://www.npmjs.com/package/sdp
-without tests or dependencies. See the commit message for version
-and commit information
+++ /dev/null
-Copyright (c) 2017 Philipp Hancke
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+++ /dev/null
-<!doctype html>
-<meta name="viewport" content="width=device-width">
-<title>Directory listing for /webrtc/third_party/sdp/</title>
-<h1>Directory listing for /webrtc/third_party/sdp/</h1>
-<ul>
-<li class="dir"><a href="/webrtc/third_party/">..</a></li>
-<li class="file"><a href="LICENSE">LICENSE</a></li>
-<li class="file"><a href="sdp.js">sdp.js</a></li>
-</ul>
+++ /dev/null
-/* eslint-env node */
-'use strict';
-
-// SDP helpers.
-var SDPUtils = {};
-
-// Generate an alphanumeric identifier for cname or mids.
-// TODO: use UUIDs instead? https://gist.github.com/jed/982883
-SDPUtils.generateIdentifier = function() {
- return Math.random().toString(36).substr(2, 10);
-};
-
-// The RTCP CNAME used by all peerconnections from the same JS.
-SDPUtils.localCName = SDPUtils.generateIdentifier();
-
-// Splits SDP into lines, dealing with both CRLF and LF.
-SDPUtils.splitLines = function(blob) {
- return blob.trim().split('\n').map(function(line) {
- return line.trim();
- });
-};
-// Splits SDP into sessionpart and mediasections. Ensures CRLF.
-SDPUtils.splitSections = function(blob) {
- var parts = blob.split('\nm=');
- return parts.map(function(part, index) {
- return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
- });
-};
-
-// returns the session description.
-SDPUtils.getDescription = function(blob) {
- var sections = SDPUtils.splitSections(blob);
- return sections && sections[0];
-};
-
-// returns the individual media sections.
-SDPUtils.getMediaSections = function(blob) {
- var sections = SDPUtils.splitSections(blob);
- sections.shift();
- return sections;
-};
-
-// Returns lines that start with a certain prefix.
-SDPUtils.matchPrefix = function(blob, prefix) {
- return SDPUtils.splitLines(blob).filter(function(line) {
- return line.indexOf(prefix) === 0;
- });
-};
-
-// Parses an ICE candidate line. Sample input:
-// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
-// rport 55996"
-SDPUtils.parseCandidate = function(line) {
- var parts;
- // Parse both variants.
- if (line.indexOf('a=candidate:') === 0) {
- parts = line.substring(12).split(' ');
- } else {
- parts = line.substring(10).split(' ');
- }
-
- var candidate = {
- foundation: parts[0],
- component: parseInt(parts[1], 10),
- protocol: parts[2].toLowerCase(),
- priority: parseInt(parts[3], 10),
- ip: parts[4],
- address: parts[4], // address is an alias for ip.
- port: parseInt(parts[5], 10),
- // skip parts[6] == 'typ'
- type: parts[7]
- };
-
- for (var i = 8; i < parts.length; i += 2) {
- switch (parts[i]) {
- case 'raddr':
- candidate.relatedAddress = parts[i + 1];
- break;
- case 'rport':
- candidate.relatedPort = parseInt(parts[i + 1], 10);
- break;
- case 'tcptype':
- candidate.tcpType = parts[i + 1];
- break;
- case 'ufrag':
- candidate.ufrag = parts[i + 1]; // for backward compability.
- candidate.usernameFragment = parts[i + 1];
- break;
- default: // extension handling, in particular ufrag
- candidate[parts[i]] = parts[i + 1];
- break;
- }
- }
- return candidate;
-};
-
-// Translates a candidate object into SDP candidate attribute.
-SDPUtils.writeCandidate = function(candidate) {
- var sdp = [];
- sdp.push(candidate.foundation);
- sdp.push(candidate.component);
- sdp.push(candidate.protocol.toUpperCase());
- sdp.push(candidate.priority);
- sdp.push(candidate.address || candidate.ip);
- sdp.push(candidate.port);
-
- var type = candidate.type;
- sdp.push('typ');
- sdp.push(type);
- if (type !== 'host' && candidate.relatedAddress &&
- candidate.relatedPort) {
- sdp.push('raddr');
- sdp.push(candidate.relatedAddress);
- sdp.push('rport');
- sdp.push(candidate.relatedPort);
- }
- if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
- sdp.push('tcptype');
- sdp.push(candidate.tcpType);
- }
- if (candidate.usernameFragment || candidate.ufrag) {
- sdp.push('ufrag');
- sdp.push(candidate.usernameFragment || candidate.ufrag);
- }
- return 'candidate:' + sdp.join(' ');
-};
-
-// Parses an ice-options line, returns an array of option tags.
-// a=ice-options:foo bar
-SDPUtils.parseIceOptions = function(line) {
- return line.substr(14).split(' ');
-};
-
-// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
-// a=rtpmap:111 opus/48000/2
-SDPUtils.parseRtpMap = function(line) {
- var parts = line.substr(9).split(' ');
- var parsed = {
- payloadType: parseInt(parts.shift(), 10) // was: id
- };
-
- parts = parts[0].split('/');
-
- parsed.name = parts[0];
- parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
- parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
- // legacy alias, got renamed back to channels in ORTC.
- parsed.numChannels = parsed.channels;
- return parsed;
-};
-
-// Generate an a=rtpmap line from RTCRtpCodecCapability or
-// RTCRtpCodecParameters.
-SDPUtils.writeRtpMap = function(codec) {
- var pt = codec.payloadType;
- if (codec.preferredPayloadType !== undefined) {
- pt = codec.preferredPayloadType;
- }
- var channels = codec.channels || codec.numChannels || 1;
- return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
- (channels !== 1 ? '/' + channels : '') + '\r\n';
-};
-
-// Parses an a=extmap line (headerextension from RFC 5285). Sample input:
-// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
-// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset
-SDPUtils.parseExtmap = function(line) {
- var parts = line.substr(9).split(' ');
- return {
- id: parseInt(parts[0], 10),
- direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',
- uri: parts[1]
- };
-};
-
-// Generates a=extmap line from RTCRtpHeaderExtensionParameters or
-// RTCRtpHeaderExtension.
-SDPUtils.writeExtmap = function(headerExtension) {
- return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
- (headerExtension.direction && headerExtension.direction !== 'sendrecv'
- ? '/' + headerExtension.direction
- : '') +
- ' ' + headerExtension.uri + '\r\n';
-};
-
-// Parses an ftmp line, returns dictionary. Sample input:
-// a=fmtp:96 vbr=on;cng=on
-// Also deals with vbr=on; cng=on
-SDPUtils.parseFmtp = function(line) {
- var parsed = {};
- var kv;
- var parts = line.substr(line.indexOf(' ') + 1).split(';');
- for (var j = 0; j < parts.length; j++) {
- kv = parts[j].trim().split('=');
- parsed[kv[0].trim()] = kv[1];
- }
- return parsed;
-};
-
-// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
-SDPUtils.writeFmtp = function(codec) {
- var line = '';
- var pt = codec.payloadType;
- if (codec.preferredPayloadType !== undefined) {
- pt = codec.preferredPayloadType;
- }
- if (codec.parameters && Object.keys(codec.parameters).length) {
- var params = [];
- Object.keys(codec.parameters).forEach(function(param) {
- if (codec.parameters[param]) {
- params.push(param + '=' + codec.parameters[param]);
- } else {
- params.push(param);
- }
- });
- line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
- }
- return line;
-};
-
-// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
-// a=rtcp-fb:98 nack rpsi
-SDPUtils.parseRtcpFb = function(line) {
- var parts = line.substr(line.indexOf(' ') + 1).split(' ');
- return {
- type: parts.shift(),
- parameter: parts.join(' ')
- };
-};
-// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
-SDPUtils.writeRtcpFb = function(codec) {
- var lines = '';
- var pt = codec.payloadType;
- if (codec.preferredPayloadType !== undefined) {
- pt = codec.preferredPayloadType;
- }
- if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
- // FIXME: special handling for trr-int?
- codec.rtcpFeedback.forEach(function(fb) {
- lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +
- (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +
- '\r\n';
- });
- }
- return lines;
-};
-
-// Parses an RFC 5576 ssrc media attribute. Sample input:
-// a=ssrc:3735928559 cname:something
-SDPUtils.parseSsrcMedia = function(line) {
- var sp = line.indexOf(' ');
- var parts = {
- ssrc: parseInt(line.substr(7, sp - 7), 10)
- };
- var colon = line.indexOf(':', sp);
- if (colon > -1) {
- parts.attribute = line.substr(sp + 1, colon - sp - 1);
- parts.value = line.substr(colon + 1);
- } else {
- parts.attribute = line.substr(sp + 1);
- }
- return parts;
-};
-
-SDPUtils.parseSsrcGroup = function(line) {
- var parts = line.substr(13).split(' ');
- return {
- semantics: parts.shift(),
- ssrcs: parts.map(function(ssrc) {
- return parseInt(ssrc, 10);
- })
- };
-};
-
-// Extracts the MID (RFC 5888) from a media section.
-// returns the MID or undefined if no mid line was found.
-SDPUtils.getMid = function(mediaSection) {
- var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];
- if (mid) {
- return mid.substr(6);
- }
-};
-
-SDPUtils.parseFingerprint = function(line) {
- var parts = line.substr(14).split(' ');
- return {
- algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.
- value: parts[1]
- };
-};
-
-// Extracts DTLS parameters from SDP media section or sessionpart.
-// FIXME: for consistency with other functions this should only
-// get the fingerprint line as input. See also getIceParameters.
-SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
- var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
- 'a=fingerprint:');
- // Note: a=setup line is ignored since we use the 'auto' role.
- // Note2: 'algorithm' is not case sensitive except in Edge.
- return {
- role: 'auto',
- fingerprints: lines.map(SDPUtils.parseFingerprint)
- };
-};
-
-// Serializes DTLS parameters to SDP.
-SDPUtils.writeDtlsParameters = function(params, setupType) {
- var sdp = 'a=setup:' + setupType + '\r\n';
- params.fingerprints.forEach(function(fp) {
- sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
- });
- return sdp;
-};
-
-// Parses a=crypto lines into
-// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members
-SDPUtils.parseCryptoLine = function(line) {
- var parts = line.substr(9).split(' ');
- return {
- tag: parseInt(parts[0], 10),
- cryptoSuite: parts[1],
- keyParams: parts[2],
- sessionParams: parts.slice(3),
- };
-};
-
-SDPUtils.writeCryptoLine = function(parameters) {
- return 'a=crypto:' + parameters.tag + ' ' +
- parameters.cryptoSuite + ' ' +
- (typeof parameters.keyParams === 'object'
- ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)
- : parameters.keyParams) +
- (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +
- '\r\n';
-};
-
-// Parses the crypto key parameters into
-// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*
-SDPUtils.parseCryptoKeyParams = function(keyParams) {
- if (keyParams.indexOf('inline:') !== 0) {
- return null;
- }
- var parts = keyParams.substr(7).split('|');
- return {
- keyMethod: 'inline',
- keySalt: parts[0],
- lifeTime: parts[1],
- mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,
- mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,
- };
-};
-
-SDPUtils.writeCryptoKeyParams = function(keyParams) {
- return keyParams.keyMethod + ':'
- + keyParams.keySalt +
- (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +
- (keyParams.mkiValue && keyParams.mkiLength
- ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength
- : '');
-};
-
-// Extracts all SDES paramters.
-SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {
- var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
- 'a=crypto:');
- return lines.map(SDPUtils.parseCryptoLine);
-};
-
-// Parses ICE information from SDP media section or sessionpart.
-// FIXME: for consistency with other functions this should only
-// get the ice-ufrag and ice-pwd lines as input.
-SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
- var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,
- 'a=ice-ufrag:')[0];
- var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,
- 'a=ice-pwd:')[0];
- if (!(ufrag && pwd)) {
- return null;
- }
- return {
- usernameFragment: ufrag.substr(12),
- password: pwd.substr(10),
- };
-};
-
-// Serializes ICE parameters to SDP.
-SDPUtils.writeIceParameters = function(params) {
- return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
- 'a=ice-pwd:' + params.password + '\r\n';
-};
-
-// Parses the SDP media section and returns RTCRtpParameters.
-SDPUtils.parseRtpParameters = function(mediaSection) {
- var description = {
- codecs: [],
- headerExtensions: [],
- fecMechanisms: [],
- rtcp: []
- };
- var lines = SDPUtils.splitLines(mediaSection);
- var mline = lines[0].split(' ');
- for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
- var pt = mline[i];
- var rtpmapline = SDPUtils.matchPrefix(
- mediaSection, 'a=rtpmap:' + pt + ' ')[0];
- if (rtpmapline) {
- var codec = SDPUtils.parseRtpMap(rtpmapline);
- var fmtps = SDPUtils.matchPrefix(
- mediaSection, 'a=fmtp:' + pt + ' ');
- // Only the first a=fmtp:<pt> is considered.
- codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
- codec.rtcpFeedback = SDPUtils.matchPrefix(
- mediaSection, 'a=rtcp-fb:' + pt + ' ')
- .map(SDPUtils.parseRtcpFb);
- description.codecs.push(codec);
- // parse FEC mechanisms from rtpmap lines.
- switch (codec.name.toUpperCase()) {
- case 'RED':
- case 'ULPFEC':
- description.fecMechanisms.push(codec.name.toUpperCase());
- break;
- default: // only RED and ULPFEC are recognized as FEC mechanisms.
- break;
- }
- }
- }
- SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
- description.headerExtensions.push(SDPUtils.parseExtmap(line));
- });
- // FIXME: parse rtcp.
- return description;
-};
-
-// Generates parts of the SDP media section describing the capabilities /
-// parameters.
-SDPUtils.writeRtpDescription = function(kind, caps) {
- var sdp = '';
-
- // Build the mline.
- sdp += 'm=' + kind + ' ';
- sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
- sdp += ' UDP/TLS/RTP/SAVPF ';
- sdp += caps.codecs.map(function(codec) {
- if (codec.preferredPayloadType !== undefined) {
- return codec.preferredPayloadType;
- }
- return codec.payloadType;
- }).join(' ') + '\r\n';
-
- sdp += 'c=IN IP4 0.0.0.0\r\n';
- sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
-
- // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
- caps.codecs.forEach(function(codec) {
- sdp += SDPUtils.writeRtpMap(codec);
- sdp += SDPUtils.writeFmtp(codec);
- sdp += SDPUtils.writeRtcpFb(codec);
- });
- var maxptime = 0;
- caps.codecs.forEach(function(codec) {
- if (codec.maxptime > maxptime) {
- maxptime = codec.maxptime;
- }
- });
- if (maxptime > 0) {
- sdp += 'a=maxptime:' + maxptime + '\r\n';
- }
- sdp += 'a=rtcp-mux\r\n';
-
- if (caps.headerExtensions) {
- caps.headerExtensions.forEach(function(extension) {
- sdp += SDPUtils.writeExtmap(extension);
- });
- }
- // FIXME: write fecMechanisms.
- return sdp;
-};
-
-// Parses the SDP media section and returns an array of
-// RTCRtpEncodingParameters.
-SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
- var encodingParameters = [];
- var description = SDPUtils.parseRtpParameters(mediaSection);
- var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
- var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
-
- // filter a=ssrc:... cname:, ignore PlanB-msid
- var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
- .map(function(line) {
- return SDPUtils.parseSsrcMedia(line);
- })
- .filter(function(parts) {
- return parts.attribute === 'cname';
- });
- var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
- var secondarySsrc;
-
- var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
- .map(function(line) {
- var parts = line.substr(17).split(' ');
- return parts.map(function(part) {
- return parseInt(part, 10);
- });
- });
- if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
- secondarySsrc = flows[0][1];
- }
-
- description.codecs.forEach(function(codec) {
- if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
- var encParam = {
- ssrc: primarySsrc,
- codecPayloadType: parseInt(codec.parameters.apt, 10)
- };
- if (primarySsrc && secondarySsrc) {
- encParam.rtx = {ssrc: secondarySsrc};
- }
- encodingParameters.push(encParam);
- if (hasRed) {
- encParam = JSON.parse(JSON.stringify(encParam));
- encParam.fec = {
- ssrc: primarySsrc,
- mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
- };
- encodingParameters.push(encParam);
- }
- }
- });
- if (encodingParameters.length === 0 && primarySsrc) {
- encodingParameters.push({
- ssrc: primarySsrc
- });
- }
-
- // we support both b=AS and b=TIAS but interpret AS as TIAS.
- var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
- if (bandwidth.length) {
- if (bandwidth[0].indexOf('b=TIAS:') === 0) {
- bandwidth = parseInt(bandwidth[0].substr(7), 10);
- } else if (bandwidth[0].indexOf('b=AS:') === 0) {
- // use formula from JSEP to convert b=AS to TIAS value.
- bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95
- - (50 * 40 * 8);
- } else {
- bandwidth = undefined;
- }
- encodingParameters.forEach(function(params) {
- params.maxBitrate = bandwidth;
- });
- }
- return encodingParameters;
-};
-
-// parses http://draft.ortc.org/#rtcrtcpparameters*
-SDPUtils.parseRtcpParameters = function(mediaSection) {
- var rtcpParameters = {};
-
- // Gets the first SSRC. Note tha with RTX there might be multiple
- // SSRCs.
- var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
- .map(function(line) {
- return SDPUtils.parseSsrcMedia(line);
- })
- .filter(function(obj) {
- return obj.attribute === 'cname';
- })[0];
- if (remoteSsrc) {
- rtcpParameters.cname = remoteSsrc.value;
- rtcpParameters.ssrc = remoteSsrc.ssrc;
- }
-
- // Edge uses the compound attribute instead of reducedSize
- // compound is !reducedSize
- var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');
- rtcpParameters.reducedSize = rsize.length > 0;
- rtcpParameters.compound = rsize.length === 0;
-
- // parses the rtcp-mux attrŅbute.
- // Note that Edge does not support unmuxed RTCP.
- var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');
- rtcpParameters.mux = mux.length > 0;
-
- return rtcpParameters;
-};
-
-// parses either a=msid: or a=ssrc:... msid lines and returns
-// the id of the MediaStream and MediaStreamTrack.
-SDPUtils.parseMsid = function(mediaSection) {
- var parts;
- var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');
- if (spec.length === 1) {
- parts = spec[0].substr(7).split(' ');
- return {stream: parts[0], track: parts[1]};
- }
- var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
- .map(function(line) {
- return SDPUtils.parseSsrcMedia(line);
- })
- .filter(function(msidParts) {
- return msidParts.attribute === 'msid';
- });
- if (planB.length > 0) {
- parts = planB[0].value.split(' ');
- return {stream: parts[0], track: parts[1]};
- }
-};
-
-// SCTP
-// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back
-// to draft-ietf-mmusic-sctp-sdp-05
-SDPUtils.parseSctpDescription = function(mediaSection) {
- var mline = SDPUtils.parseMLine(mediaSection);
- var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');
- var maxMessageSize;
- if (maxSizeLine.length > 0) {
- maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10);
- }
- if (isNaN(maxMessageSize)) {
- maxMessageSize = 65536;
- }
- var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');
- if (sctpPort.length > 0) {
- return {
- port: parseInt(sctpPort[0].substr(12), 10),
- protocol: mline.fmt,
- maxMessageSize: maxMessageSize
- };
- }
- var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');
- if (sctpMapLines.length > 0) {
- var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0]
- .substr(10)
- .split(' ');
- return {
- port: parseInt(parts[0], 10),
- protocol: parts[1],
- maxMessageSize: maxMessageSize
- };
- }
-};
-
-// SCTP
-// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers
-// support by now receiving in this format, unless we originally parsed
-// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line
-// protocol of DTLS/SCTP -- without UDP/ or TCP/)
-SDPUtils.writeSctpDescription = function(media, sctp) {
- var output = [];
- if (media.protocol !== 'DTLS/SCTP') {
- output = [
- 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n',
- 'c=IN IP4 0.0.0.0\r\n',
- 'a=sctp-port:' + sctp.port + '\r\n'
- ];
- } else {
- output = [
- 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n',
- 'c=IN IP4 0.0.0.0\r\n',
- 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n'
- ];
- }
- if (sctp.maxMessageSize !== undefined) {
- output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n');
- }
- return output.join('');
-};
-
-// Generate a session ID for SDP.
-// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1
-// recommends using a cryptographically random +ve 64-bit value
-// but right now this should be acceptable and within the right range
-SDPUtils.generateSessionId = function() {
- return Math.random().toString().substr(2, 21);
-};
-
-// Write boilder plate for start of SDP
-// sessId argument is optional - if not supplied it will
-// be generated randomly
-// sessVersion is optional and defaults to 2
-// sessUser is optional and defaults to 'thisisadapterortc'
-SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {
- var sessionId;
- var version = sessVer !== undefined ? sessVer : 2;
- if (sessId) {
- sessionId = sessId;
- } else {
- sessionId = SDPUtils.generateSessionId();
- }
- var user = sessUser || 'thisisadapterortc';
- // FIXME: sess-id should be an NTP timestamp.
- return 'v=0\r\n' +
- 'o=' + user + ' ' + sessionId + ' ' + version +
- ' IN IP4 127.0.0.1\r\n' +
- 's=-\r\n' +
- 't=0 0\r\n';
-};
-
-SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
- var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
-
- // Map ICE parameters (ufrag, pwd) to SDP.
- sdp += SDPUtils.writeIceParameters(
- transceiver.iceGatherer.getLocalParameters());
-
- // Map DTLS parameters to SDP.
- sdp += SDPUtils.writeDtlsParameters(
- transceiver.dtlsTransport.getLocalParameters(),
- type === 'offer' ? 'actpass' : 'active');
-
- sdp += 'a=mid:' + transceiver.mid + '\r\n';
-
- if (transceiver.direction) {
- sdp += 'a=' + transceiver.direction + '\r\n';
- } else if (transceiver.rtpSender && transceiver.rtpReceiver) {
- sdp += 'a=sendrecv\r\n';
- } else if (transceiver.rtpSender) {
- sdp += 'a=sendonly\r\n';
- } else if (transceiver.rtpReceiver) {
- sdp += 'a=recvonly\r\n';
- } else {
- sdp += 'a=inactive\r\n';
- }
-
- if (transceiver.rtpSender) {
- // spec.
- var msid = 'msid:' + stream.id + ' ' +
- transceiver.rtpSender.track.id + '\r\n';
- sdp += 'a=' + msid;
-
- // for Chrome.
- sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
- ' ' + msid;
- if (transceiver.sendEncodingParameters[0].rtx) {
- sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
- ' ' + msid;
- sdp += 'a=ssrc-group:FID ' +
- transceiver.sendEncodingParameters[0].ssrc + ' ' +
- transceiver.sendEncodingParameters[0].rtx.ssrc +
- '\r\n';
- }
- }
- // FIXME: this should be written by writeRtpDescription.
- sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
- ' cname:' + SDPUtils.localCName + '\r\n';
- if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
- sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
- ' cname:' + SDPUtils.localCName + '\r\n';
- }
- return sdp;
-};
-
-// Gets the direction from the mediaSection or the sessionpart.
-SDPUtils.getDirection = function(mediaSection, sessionpart) {
- // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
- var lines = SDPUtils.splitLines(mediaSection);
- for (var i = 0; i < lines.length; i++) {
- switch (lines[i]) {
- case 'a=sendrecv':
- case 'a=sendonly':
- case 'a=recvonly':
- case 'a=inactive':
- return lines[i].substr(2);
- default:
- // FIXME: What should happen here?
- }
- }
- if (sessionpart) {
- return SDPUtils.getDirection(sessionpart);
- }
- return 'sendrecv';
-};
-
-SDPUtils.getKind = function(mediaSection) {
- var lines = SDPUtils.splitLines(mediaSection);
- var mline = lines[0].split(' ');
- return mline[0].substr(2);
-};
-
-SDPUtils.isRejected = function(mediaSection) {
- return mediaSection.split(' ', 2)[1] === '0';
-};
-
-SDPUtils.parseMLine = function(mediaSection) {
- var lines = SDPUtils.splitLines(mediaSection);
- var parts = lines[0].substr(2).split(' ');
- return {
- kind: parts[0],
- port: parseInt(parts[1], 10),
- protocol: parts[2],
- fmt: parts.slice(3).join(' ')
- };
-};
-
-SDPUtils.parseOLine = function(mediaSection) {
- var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];
- var parts = line.substr(2).split(' ');
- return {
- username: parts[0],
- sessionId: parts[1],
- sessionVersion: parseInt(parts[2], 10),
- netType: parts[3],
- addressType: parts[4],
- address: parts[5]
- };
-};
-
-// a very naive interpretation of a valid SDP.
-SDPUtils.isValidSDP = function(blob) {
- if (typeof blob !== 'string' || blob.length === 0) {
- return false;
- }
- var lines = SDPUtils.splitLines(blob);
- for (var i = 0; i < lines.length; i++) {
- if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {
- return false;
- }
- // TODO: check the modifier a bit more.
- }
- return true;
-};
-
-// Expose public methods.
-if (typeof module === 'object') {
- module.exports = SDPUtils;
-}
--- /dev/null
+This test suite comes from\r
+https://github.com/web-platform-tests/wpt/tree/master/webrtc/\r
+with tizen namespace and application id added into config.xml\r
+\r
+These tests are copyright by W3C and/or the author listed in the test\r
+file. The tests are dual-licensed under the W3C Test Suite License:\r
+http://www.w3.org/Consortium/Legal/2008/04-testsuite-license\r
+and the BSD 3-clause License:\r
+http://www.w3.org/Consortium/Legal/2008/03-bsd-license\r
+under W3C's test suite licensing policy:\r
+http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright\r
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCCertificate persistent Tests</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/get-host-info.sub.js"></script>
+<body>
+<script>
+ function findMatchingFingerprint(fingerprints, fingerprint) {
+ for (let f of fingerprints) {
+ if (f.value == fingerprint.value && f.algorithm == fingerprint.algorithm)
+ return true;
+ }
+ return false;
+ }
+
+ function with_iframe(url) {
+ return new Promise(function(resolve) {
+ var frame = document.createElement('iframe');
+ frame.src = url;
+ frame.onload = function() { resolve(frame); };
+ document.body.appendChild(frame);
+ });
+ }
+
+ function testPostMessageCertificate(isCrossOrigin) {
+ promise_test(async t => {
+ let certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256' });
+
+ let url = "resources/RTCCertificate-postMessage-iframe.html";
+ if (isCrossOrigin)
+ url = get_host_info().HTTP_REMOTE_ORIGIN + "/webrtc/" + url;
+
+ let iframe = await with_iframe(url);
+
+ let promise = new Promise((resolve, reject) => {
+ window.onmessage = (event) => {
+ resolve(event.data);
+ };
+ t.step_timeout(() => reject("Timed out waiting for frame to send back certificate"), 5000);
+ });
+ iframe.contentWindow.postMessage(certificate, "*");
+ let certificate2 = await promise;
+
+ const pc1 = new RTCPeerConnection({certificates: [certificate]});
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection({certificates: [certificate2]});
+ t.add_cleanup(() => pc2.close());
+
+ assert_equals(certificate.expires, certificate2.expires);
+ for (let fingerprint of certificate2.getFingerprints())
+ assert_true(findMatchingFingerprint(certificate.getFingerprints(), fingerprint), "check fingerprints");
+
+ iframe.remove();
+ }, "Check " + (isCrossOrigin ? "cross-origin" : "same-origin") + " RTCCertificate serialization");
+ }
+
+ testPostMessageCertificate(false);
+ // testPostMessageCertificate(true);
+
+</script>
+</body>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCCertificate Tests</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the Candidate Recommendation:
+ // https://www.w3.org/TR/webrtc/
+
+ /*
+ 4.2.1. RTCConfiguration Dictionary
+ dictionary RTCConfiguration {
+ sequence<RTCCertificate> certificates;
+ ...
+ };
+
+ certificates of type sequence<RTCCertificate>
+ If this value is absent, then a default set of certificates is
+ generated for each RTCPeerConnection instance.
+
+ The value for this configuration option cannot change after its
+ value is initially selected.
+
+ 4.10.2. RTCCertificate Interface
+ interface RTCCertificate {
+ readonly attribute DOMTimeStamp expires;
+ static sequence<AlgorithmIdentifier> getSupportedAlgorithms();
+ sequence<RTCDtlsFingerprint> getFingerprints();
+ };
+
+ 5.5.1 The RTCDtlsFingerprint Dictionary
+ dictionary RTCDtlsFingerprint {
+ DOMString algorithm;
+ DOMString value;
+ };
+
+ [RFC4572] Comedia over TLS in SDP
+ 5. Fingerprint Attribute
+ Figure 2. Augmented Backus-Naur Syntax for the Fingerprint Attribute
+
+ attribute =/ fingerprint-attribute
+
+ fingerprint-attribute = "fingerprint" ":" hash-func SP fingerprint
+
+ hash-func = "sha-1" / "sha-224" / "sha-256" /
+ "sha-384" / "sha-512" /
+ "md5" / "md2" / token
+ ; Additional hash functions can only come
+ ; from updates to RFC 3279
+
+ fingerprint = 2UHEX *(":" 2UHEX)
+ ; Each byte in upper-case hex, separated
+ ; by colons.
+
+ UHEX = DIGIT / %x41-46 ; A-F uppercase
+ */
+
+ // Helper function to generate certificate with a set of
+ // default parameters
+ function generateCertificate() {
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256'
+ });
+ }
+
+ // Helper function that takes in an RTCDtlsFingerprint
+ // and return an a=fingerprint SDP line
+ function fingerprintToSdpLine(fingerprint) {
+ return `\r\na=fingerprint:${fingerprint.algorithm} ${fingerprint.value.toUpperCase()}\r\n`;
+ }
+
+ // Assert that an SDP string has fingerprint line for all the cert's fingerprints
+ function assert_sdp_has_cert_fingerprints(sdp, cert) {
+ for(const fingerprint of cert.getFingerprints()) {
+ const fingerprintLine = fingerprintToSdpLine(fingerprint);
+ assert_true(sdp.includes(fingerprintLine),
+ 'Expect fingerprint line to be found in SDP');
+ }
+ }
+
+ /*
+ 4.3.1. Operation
+ When the RTCPeerConnection() constructor is invoked
+ 2. If the certificates value in configuration is non-empty,
+ check that the expires on each value is in the future.
+ If a certificate has expired, throw an InvalidAccessError;
+ otherwise, store the certificates. If no certificates value
+ was specified, one or more new RTCCertificate instances are
+ generated for use with this RTCPeerConnection instance.
+ This may happen asynchronously and the value of certificates
+ remains undefined for the subsequent steps.
+ */
+ promise_test(t => {
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256',
+ expires: 0
+ }).then(cert => {
+ assert_less_than_equal(cert.expires, Date.now());
+ assert_throws_dom('InvalidAccessError', () =>
+ new RTCPeerConnection({ certificates: [cert] }));
+ });
+ }, 'Constructing RTCPeerConnection with expired certificate should reject with InvalidAccessError');
+
+ /*
+ 4.3.2 Interface Definition
+ setConfiguration
+ 4. If configuration.certificates is set and the set of
+ certificates differs from the ones used when connection
+ was constructed, throw an InvalidModificationError.
+ */
+ promise_test(t => {
+ return Promise.all([
+ generateCertificate(),
+ generateCertificate()
+ ]).then(([cert1, cert2]) => {
+ const pc = new RTCPeerConnection({
+ certificates: [cert1]
+ });
+
+ // should not throw
+ pc.setConfiguration({
+ certificates: [cert1]
+ });
+
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({
+ certificates: [cert2]
+ }));
+
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({
+ certificates: [cert1, cert2]
+ }));
+ });
+ }, 'Calling setConfiguration with different set of certs should reject with InvalidModificationError');
+
+ /*
+ 4.10.2. RTCCertificate Interface
+ getFingerprints
+ Returns the list of certificate fingerprints, one of which is
+ computed with the digest algorithm used in the certificate signature.
+
+ 5.5.1 The RTCDtlsFingerprint Dictionary
+ algorithm of type DOMString
+ One of the the hash function algorithms defined in the 'Hash function
+ Textual Names' registry, initially specified in [RFC4572] Section 8.
+ As noted in [JSEP] Section 5.2.1, the digest algorithm used for the
+ fingerprint matches that used in the certificate signature.
+
+ value of type DOMString
+ The value of the certificate fingerprint in lowercase hex string as
+ expressed utilizing the syntax of 'fingerprint' in [ RFC4572] Section 5.
+
+ */
+ promise_test(t => {
+ return generateCertificate()
+ .then(cert => {
+ assert_idl_attribute(cert, 'getFingerprints');
+
+ const fingerprints = cert.getFingerprints();
+ assert_true(Array.isArray(fingerprints),
+ 'Expect fingerprints to return an array');
+
+ assert_greater_than_equal(fingerprints.length, 1,
+ 'Expect at last one fingerprint in array');
+
+ for(const fingerprint of fingerprints) {
+ assert_equals(typeof fingerprint, 'object',
+ 'Expect fingerprint to be an object (dictionary)');
+
+ // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xml
+ const algorithms = ['md2', 'md5', 'sha-1', 'sha-224', 'sha-256', 'sha-384', 'sha-512'];
+ assert_in_array(fingerprint.algorithm, algorithms,
+ 'Expect fingerprint.algorithm to be string of algorithm identifier');
+
+ assert_true(/^([0-9a-f]{2}\:)+[0-9a-f]{2}$/.test(fingerprint.value),
+ 'Expect fingerprint.value to be lowercase hexadecimal separated by colon');
+ }
+ });
+ }, 'RTCCertificate should have at least one fingerprint');
+
+ /*
+ 4.3.2 Interface Definition
+ createOffer
+ The value for certificates in the RTCConfiguration for the
+ RTCPeerConnection is used to produce a set of certificate
+ fingerprints. These certificate fingerprints are used in the
+ construction of SDP and as input to requests for identity
+ assertions.
+
+ [JSEP]
+ 5.2.1. Initial Offers
+ For DTLS, all m= sections MUST use all the certificate(s) that have
+ been specified for the PeerConnection; as a result, they MUST all
+ have the same [I-D.ietf-mmusic-4572-update] fingerprint value(s), or
+ these value(s) MUST be session-level attributes.
+
+ The following attributes, which are of category IDENTICAL or
+ TRANSPORT, MUST appear only in "m=" sections which either have a
+ unique address or which are associated with the bundle-tag. (In
+ initial offers, this means those "m=" sections which do not contain
+ an "a=bundle-only" attribute.)
+
+ - An "a=fingerprint" line for each of the endpoint's certificates,
+ as specified in [RFC4572], Section 5; the digest algorithm used
+ for the fingerprint MUST match that used in the certificate
+ signature.
+
+ Each m= section which is not bundled into another m= section, MUST
+ contain the following attributes (which are of category IDENTICAL or
+ TRANSPORT):
+
+ - An "a=fingerprint" line for each of the endpoint's certificates,
+ as specified in [RFC4572], Section 5; the digest algorithm used
+ for the fingerprint MUST match that used in the certificate
+ signature.
+ */
+ promise_test(t => {
+ return generateCertificate()
+ .then(cert => {
+ const pc = new RTCPeerConnection({
+ certificates: [cert]
+ });
+ pc.createDataChannel('test');
+
+ return pc.createOffer()
+ .then(offer => {
+ assert_sdp_has_cert_fingerprints(offer.sdp, cert);
+ });
+ });
+ }, 'RTCPeerConnection({ certificates }) should generate offer SDP with fingerprint of provided certificate');
+
+ /*
+ TODO
+
+ 4.10.2. RTCCertificate Interface
+ getSupportedAlgorithms
+ Returns a sequence providing a representative set of supported
+ certificate algorithms. At least one algorithm MUST be returned.
+
+ The RTCCertificate object can be stored and retrieved from persistent
+ storage by an application. When a user agent is required to obtain a
+ structured clone [HTML5] of a RTCCertificate object, it performs the
+ following steps:
+ 1. Let input and memory be the corresponding inputs defined by the
+ internal structured cloning algorithm, where input represents a
+ RTCCertificate object to be cloned.
+ 2. Let output be a newly constructed RTCCertificate object.
+ 3. Copy the value of the expires attribute from input to output.
+ 4. Let the [[certificate]] internal slot of output be set to the
+ result of invoking the internal structured clone algorithm
+ recursively on the corresponding internal slots of input, with
+ the slot contents as the new " input" argument and memory as
+ the new " memory" argument.
+ 5. Let the [[handle]] internal slot of output refer to the same
+ private keying material represented by the [[handle]] internal
+ slot of input.
+ */
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCConfiguration bundlePolicy</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ ...
+ RTCConfiguration getConfiguration();
+ void setConfiguration(RTCConfiguration configuration);
+ };
+
+ 4.2.1. RTCConfiguration Dictionary
+ dictionary RTCConfiguration {
+ RTCBundlePolicy bundlePolicy = "balanced";
+ ...
+ };
+
+ 4.2.6. RTCBundlePolicy Enum
+ enum RTCBundlePolicy {
+ "balanced",
+ "max-compat",
+ "max-bundle"
+ };
+ */
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
+ }, 'Default bundlePolicy should be balanced');
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: undefined });
+ assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
+ }, `new RTCPeerConnection({ bundlePolicy: undefined }) should have bundlePolicy balanced`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
+ assert_equals(pc.getConfiguration().bundlePolicy, 'balanced');
+ }, `new RTCPeerConnection({ bundlePolicy: 'balanced' }) should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-compat' });
+ assert_equals(pc.getConfiguration().bundlePolicy, 'max-compat');
+ }, `new RTCPeerConnection({ bundlePolicy: 'max-compat' }) should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
+ assert_equals(pc.getConfiguration().bundlePolicy, 'max-bundle');
+ }, `new RTCPeerConnection({ bundlePolicy: 'max-bundle' }) should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ pc.setConfiguration({});
+ }, 'setConfiguration({}) with initial default bundlePolicy balanced should succeed');
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
+ pc.setConfiguration({});
+ }, 'setConfiguration({}) with initial bundlePolicy balanced should succeed');
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ pc.setConfiguration({ bundlePolicy: 'balanced' });
+ }, 'setConfiguration({ bundlePolicy: balanced }) with initial default bundlePolicy balanced should succeed');
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'balanced' });
+ pc.setConfiguration({ bundlePolicy: 'balanced' });
+ }, `setConfiguration({ bundlePolicy: 'balanced' }) with initial bundlePolicy balanced should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-compat' });
+ pc.setConfiguration({ bundlePolicy: 'max-compat' });
+ }, `setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-compat should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
+ pc.setConfiguration({ bundlePolicy: 'max-bundle' });
+ }, `setConfiguration({ bundlePolicy: 'max-bundle' }) with initial bundlePolicy max-bundle should succeed`);
+
+ test(() => {
+ assert_throws_js(TypeError, () =>
+ new RTCPeerConnection({ bundlePolicy: null }));
+ }, `new RTCPeerConnection({ bundlePolicy: null }) should throw TypeError`);
+
+ test(() => {
+ assert_throws_js(TypeError, () =>
+ new RTCPeerConnection({ bundlePolicy: 'invalid' }));
+ }, `new RTCPeerConnection({ bundlePolicy: 'invalid' }) should throw TypeError`);
+
+ /*
+ 4.3.2. Interface Definition
+ To set a configuration
+ 5. If configuration.bundlePolicy is set and its value differs from the
+ connection's bundle policy, throw an InvalidModificationError.
+ */
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
+ assert_idl_attribute(pc, 'setConfiguration');
+
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({ bundlePolicy: 'max-compat' }));
+ }, `setConfiguration({ bundlePolicy: 'max-compat' }) with initial bundlePolicy max-bundle should throw InvalidModificationError`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ bundlePolicy: 'max-bundle' });
+ assert_idl_attribute(pc, 'setConfiguration');
+
+ // the default value for bundlePolicy is balanced
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({}));
+ }, `setConfiguration({}) with initial bundlePolicy max-bundle should throw InvalidModificationError`);
+
+ /*
+ Coverage Report
+ Tested 2
+ Total 2
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<!--
+4.2.1 RTCConfiguration Dictionary
+
+ The RTCConfiguration defines a set of parameters to configure how the peer to peer communication established via RTCPeerConnection is established or re-established.
+
+ ...
+
+ iceCandidatePoolSize of type octet, defaulting to 0
+ Size of the prefetched ICE pool as defined in [JSEP] (section 3.5.4. and section 4.1.1.).
+-->
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+
+/*
+
+dictionary RTCConfiguration {
+ ...
+ [EnforceRange]
+ octet iceCandidatePoolSize = 0;
+};
+
+... of type octet
+*/
+test(() => {
+ const pc = new RTCPeerConnection();
+ assert_idl_attribute(pc, "getConfiguration");
+ assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
+}, "Initialize a new RTCPeerConnection with no iceCandidatePoolSize");
+
+test(() => {
+ const pc = new RTCPeerConnection({
+ iceCandidatePoolSize: 0
+ });
+ assert_idl_attribute(pc, "getConfiguration");
+ assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
+}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 0");
+
+test(() => {
+ const pc = new RTCPeerConnection({
+ iceCandidatePoolSize: 255
+ });
+ assert_idl_attribute(pc, "getConfiguration");
+ assert_equals(pc.getConfiguration().iceCandidatePoolSize, 255);
+}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 255");
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new RTCPeerConnection({
+ iceCandidatePoolSize: -1
+ });
+ });
+}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: -1 (Out Of Range)");
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new RTCPeerConnection({
+ iceCandidatePoolSize: 256
+ });
+ });
+}, "Initialize a new RTCPeerConnection with iceCandidatePoolSize: 256 (Out Of Range)");
+
+
+/*
+Reconfiguration
+*/
+
+test(() => {
+ const pc = new RTCPeerConnection();
+ assert_idl_attribute(pc, "getConfiguration");
+ assert_idl_attribute(pc, "setConfiguration");
+ pc.setConfiguration({
+ iceCandidatePoolSize: 0
+ });
+ assert_equals(pc.getConfiguration().iceCandidatePoolSize, 0);
+}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 0");
+
+test(() => {
+ const pc = new RTCPeerConnection();
+ assert_idl_attribute(pc, "getConfiguration");
+ assert_idl_attribute(pc, "setConfiguration");
+ pc.setConfiguration({
+ iceCandidatePoolSize: 255
+ });
+ assert_equals(pc.getConfiguration().iceCandidatePoolSize, 255);
+}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 255");
+
+/*
+The following tests include an explicit assertion for the existence of a
+setConfiguration function to prevent the assert_throws_js from catching the
+TypeError object that will be thrown when attempting to call the
+non-existent setConfiguration method (in cases where it has not yet
+been implemented). Without this check, these tests will pass incorrectly.
+*/
+
+test(() => {
+ const pc = new RTCPeerConnection();
+ assert_equals(typeof pc.setConfiguration, "function", "RTCPeerConnection.prototype.setConfiguration is not implemented");
+ assert_throws_js(TypeError, () => {
+ pc.setConfiguration({
+ iceCandidatePoolSize: -1
+ });
+ });
+}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to -1 (Out Of Range)");
+
+test(() => {
+ const pc = new RTCPeerConnection();
+ assert_equals(typeof pc.setConfiguration, "function", "RTCPeerConnection.prototype.setConfiguration is not implemented");
+ assert_throws_js(TypeError, () => {
+ pc.setConfiguration({
+ iceCandidatePoolSize: 256
+ });
+ });
+}, "Reconfigure RTCPeerConnection instance iceCandidatePoolSize to 256 (Out Of Range)");
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCConfiguration iceServers</title>
+<script src='../../resources/testharness.js'></script>
+<script src='../../resources/testharnessreport.js'></script>
+<script src='support/RTCConfiguration-helper.js'></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor's draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ // The following helper function is called from
+ // RTCConfiguration-helper.js:
+ // config_test
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ ...
+ };
+ 4.2.1. RTCConfiguration Dictionary
+ dictionary RTCConfiguration {
+ sequence<RTCIceServer> iceServers = [];
+ ...
+ };
+ 4.2.4. RTCIceServer Dictionary
+ dictionary RTCIceServer {
+ required (DOMString or sequence<DOMString>) urls;
+ DOMString username;
+ DOMString credential;
+ };
+ */
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ assert_array_equals(pc.getConfiguration().iceServers, []);
+ }, 'new RTCPeerConnection() should have default configuration.iceServers of undefined');
+
+ config_test(makePc => {
+ makePc({});
+ }, '{} should succeed');
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceServers: null }));
+ }, '{ iceServers: null } should throw TypeError');
+
+ config_test(makePc => {
+ const pc = makePc({ iceServers: undefined });
+ assert_array_equals(pc.getConfiguration().iceServers, []);
+ }, '{ iceServers: undefined } should succeed');
+
+ config_test(makePc => {
+ const pc = makePc({ iceServers: [] });
+ assert_array_equals(pc.getConfiguration().iceServers, []);
+ }, '{ iceServers: [] } should succeed');
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceServers: [null] }));
+ }, '{ iceServers: [null] } should throw TypeError');
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceServers: [undefined] }));
+ }, '{ iceServers: [undefined] } should throw TypeError');
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceServers: [{}] }));
+ }, '{ iceServers: [{}] } should throw TypeError');
+
+ config_test(makePc => {
+ const pc = makePc({ iceServers: [{
+ urls: 'stun:stun1.example.net'
+ }] });
+
+ const { iceServers } = pc.getConfiguration();
+ assert_equals(iceServers.length, 1);
+
+ const server = iceServers[0];
+ assert_array_equals(server.urls, ['stun:stun1.example.net']);
+
+ }, `with stun server should succeed`);
+
+ config_test(makePc => {
+ const pc = makePc({ iceServers: [{
+ urls: ['stun:stun1.example.net']
+ }] });
+
+ const { iceServers } = pc.getConfiguration();
+ assert_equals(iceServers.length, 1);
+
+ const server = iceServers[0];
+ assert_array_equals(server.urls, ['stun:stun1.example.net']);
+
+ }, `with stun server array should succeed`);
+
+ config_test(makePc => {
+ const pc = makePc({ iceServers: [{
+ urls: 'turn:turn.example.org',
+ username: 'user',
+ credential: 'cred'
+ }] });
+
+ const { iceServers } = pc.getConfiguration();
+ assert_equals(iceServers.length, 1);
+
+ const server = iceServers[0];
+ assert_array_equals(server.urls, ['turn:turn.example.org']);
+ assert_equals(server.username, 'user');
+ assert_equals(server.credential, 'cred');
+
+ }, `with turn server, username, credential should succeed`);
+
+ /*
+ 4.3.2. To set a configuration
+ 11.4. If scheme name is turn or turns, and either of server.username or
+ server.credential are omitted, then throw an InvalidAccessError.
+ */
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turn:turn.example.net'
+ }] }));
+ }, 'with turn server and no credentials should throw InvalidAccessError');
+
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turn:turn.example.net',
+ username: 'user'
+ }] }));
+ }, 'with turn server and only username should throw InvalidAccessError');
+
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turn:turn.example.net',
+ credential: 'cred'
+ }] }));
+ }, 'with turn server and only credential should throw InvalidAccessError');
+
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turns:turn.example.net'
+ }] }));
+ }, 'with turns server and no credentials should throw InvalidAccessError');
+
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turns:turn.example.net',
+ username: 'user'
+ }] }));
+ }, 'with turns server and only username should throw InvalidAccessError');
+
+ config_test(makePc => {
+ assert_throws_dom('InvalidAccessError', () =>
+ makePc({ iceServers: [{
+ urls: 'turns:turn.example.net',
+ credential: 'cred'
+ }] }));
+ }, 'with turns server and only credential should throw InvalidAccessError');
+
+ /*
+ 4.3.2. To set a configuration
+ 11.3. For each url in server.urls parse url and obtain scheme name.
+ - If the scheme name is not implemented by the browser, throw a SyntaxError.
+ - or if parsing based on the syntax defined in [ RFC7064] and [RFC7065] fails,
+ throw a SyntaxError.
+ [RFC7064] URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol
+ 3.1. URI Scheme Syntax
+ stunURI = scheme ":" host [ ":" port ]
+ scheme = "stun" / "stuns"
+ [RFC7065] Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers
+ 3.1. URI Scheme Syntax
+ turnURI = scheme ":" host [ ":" port ]
+ [ "?transport=" transport ]
+ scheme = "turn" / "turns"
+ transport = "udp" / "tcp" / transport-ext
+ transport-ext = 1*unreserved
+ */
+ config_test(makePc => {
+ assert_throws_dom("SyntaxError", () =>
+ makePc({ iceServers: [{
+ urls: ''
+ }] }));
+ }, 'with "" url should throw SyntaxError');
+
+ config_test(makePc => {
+ assert_throws_dom("SyntaxError", () =>
+ makePc({ iceServers: [{
+ urls: ['stun:stun1.example.net', '']
+ }] }));
+ }, 'with ["stun:stun1.example.net", ""] url should throw SyntaxError');
+
+ config_test(makePc => {
+ assert_throws_dom("SyntaxError", () =>
+ makePc({ iceServers: [{
+ urls: 'relative-url'
+ }] }));
+ }, 'with relative url should throw SyntaxError');
+
+ config_test(makePc => {
+ assert_throws_dom("SyntaxError", () =>
+ makePc({ iceServers: [{
+ urls: 'http://example.com'
+ }] }));
+ }, 'with http url should throw SyntaxError');
+
+</script>
\ No newline at end of file
--- /dev/null
+<!doctype html>
+<meta name="timeout" content="long">
+<title>RTCConfiguration iceTransportPolicy</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCConfiguration-helper.js"></script>
+<script src="support/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 function is called from RTCConfiguration-helper.js:
+ // config_test
+
+ /*
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ RTCConfiguration getConfiguration();
+ void setConfiguration(RTCConfiguration configuration);
+ ...
+ };
+
+ dictionary RTCConfiguration {
+ sequence<RTCIceServer> iceServers;
+ RTCIceTransportPolicy iceTransportPolicy = "all";
+ };
+
+ enum RTCIceTransportPolicy {
+ "relay",
+ "all"
+ };
+ */
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+ }, `new RTCPeerConnection() should have default iceTransportPolicy all`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: undefined });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+ }, `new RTCPeerConnection({ iceTransportPolicy: undefined }) should have default iceTransportPolicy all`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: 'all' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+ }, `new RTCPeerConnection({ iceTransportPolicy: 'all' }) should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
+ }, `new RTCPeerConnection({ iceTransportPolicy: 'relay' }) should succeed`);
+
+ /*
+ 4.3.2. Set a configuration
+ 8. Set the ICE Agent's ICE transports setting to the value of
+ configuration.iceTransportPolicy. As defined in [JSEP] (section 4.1.16.),
+ if the new ICE transports setting changes the existing setting, no action
+ will be taken until the next gathering phase. If a script wants this to
+ happen immediately, it should do an ICE restart.
+ */
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: 'all' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+
+ pc.setConfiguration({ iceTransportPolicy: 'relay' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
+ }, `setConfiguration({ iceTransportPolicy: 'relay' }) with initial iceTransportPolicy all should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
+
+ pc.setConfiguration({ iceTransportPolicy: 'all' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+ }, `setConfiguration({ iceTransportPolicy: 'all' }) with initial iceTransportPolicy relay should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ iceTransportPolicy: 'relay' });
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'relay');
+
+ // default value for iceTransportPolicy is all
+ pc.setConfiguration({});
+ assert_equals(pc.getConfiguration().iceTransportPolicy, 'all');
+ }, `setConfiguration({}) with initial iceTransportPolicy relay should set new value to all`);
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceTransportPolicy: 'invalid' }));
+ }, `with invalid iceTransportPolicy should throw TypeError`);
+
+ // "none" is in Blink and Gecko's IDL, but not in the spec.
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceTransportPolicy: 'none' }));
+ }, `with none iceTransportPolicy should throw TypeError`);
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ iceTransportPolicy: null }));
+ }, `with null iceTransportPolicy should throw TypeError`);
+
+</script>
--- /dev/null
+<!doctype html>
+<title>RTCConfiguration rtcpMuxPolicy</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCConfiguration-helper.js"></script>
+<script src="support/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 function is called from RTCConfiguration-helper.js:
+ // config_test
+
+ /*
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ RTCConfiguration getConfiguration();
+ void setConfiguration(RTCConfiguration configuration);
+ ...
+ };
+
+ dictionary RTCConfiguration {
+ RTCRtcpMuxPolicy rtcpMuxPolicy = "require";
+ ...
+ };
+
+ enum RTCRtcpMuxPolicy {
+ "negotiate",
+ "require"
+ };
+ */
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
+ }, `new RTCPeerConnection() should have default rtcpMuxPolicy require`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ rtcpMuxPolicy: undefined });
+ assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
+ }, `new RTCPeerConnection({ rtcpMuxPolicy: undefined }) should have default rtcpMuxPolicy require`);
+
+ test(() => {
+ const pc = new RTCPeerConnection({ rtcpMuxPolicy: 'require' });
+ assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'require');
+ }, `new RTCPeerConnection({ rtcpMuxPolicy: 'require' }) should succeed`);
+
+ /*
+ 4.3.1.1. Constructor
+ 3. If configuration.rtcpMuxPolicy is negotiate, and the user agent does not
+ implement non-muxed RTCP, throw a NotSupportedError.
+ */
+ test(() => {
+ let pc;
+ try {
+ pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
+ } catch(err) {
+ // NotSupportedError is a DOMException with code 9
+ if(err.code === 9 && err.name === 'NotSupportedError') {
+ // ignore error and pass test if negotiate is not supported
+ return;
+ } else {
+ throw err;
+ }
+ }
+
+ assert_equals(pc.getConfiguration().rtcpMuxPolicy, 'negotiate');
+
+ }, `new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' }) may succeed or throw NotSupportedError`);
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ rtcpMuxPolicy: null }));
+ }, `with { rtcpMuxPolicy: null } should throw TypeError`);
+
+ config_test(makePc => {
+ assert_throws_js(TypeError, () =>
+ makePc({ rtcpMuxPolicy: 'invalid' }));
+ }, `with { rtcpMuxPolicy: 'invalid' } should throw TypeError`);
+
+ /*
+ 4.3.2. Set a configuration
+ 6. If configuration.rtcpMuxPolicy is set and its value differs from the
+ connection's rtcpMux policy, throw an InvalidModificationError.
+ */
+
+ test(() => {
+ const pc = new RTCPeerConnection({ rtcpMuxPolicy: 'require' });
+ assert_idl_attribute(pc, 'setConfiguration');
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({ rtcpMuxPolicy: 'negotiate' }));
+
+ }, `setConfiguration({ rtcpMuxPolicy: 'negotiate' }) with initial rtcpMuxPolicy require should throw InvalidModificationError`);
+
+ test(() => {
+ let pc;
+ try {
+ pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
+ } catch(err) {
+ // NotSupportedError is a DOMException with code 9
+ if(err.code === 9 && err.name === 'NotSupportedError') {
+ // ignore error and pass test if negotiate is not supported
+ return;
+ } else {
+ throw err;
+ }
+ }
+
+ assert_idl_attribute(pc, 'setConfiguration');
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({ rtcpMuxPolicy: 'require' }));
+
+ }, `setConfiguration({ rtcpMuxPolicy: 'require' }) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError`);
+
+ test(() => {
+ let pc;
+ try {
+ pc = new RTCPeerConnection({ rtcpMuxPolicy: 'negotiate' });
+ } catch(err) {
+ // NotSupportedError is a DOMException with code 9
+ if(err.code === 9 && err.name === 'NotSupportedError') {
+ // ignore error and pass test if negotiate is not supported
+ return;
+ } else {
+ throw err;
+ }
+ }
+
+ assert_idl_attribute(pc, 'setConfiguration');
+ // default value for rtcpMuxPolicy is require
+ assert_throws_dom('InvalidModificationError', () =>
+ pc.setConfiguration({}));
+
+ }, `setConfiguration({}) with initial rtcpMuxPolicy negotiate should throw InvalidModificationError`);
+
+ /*
+ Coverage Report
+
+ Tested 2
+ Total 2
+ */
+ const FINGERPRINT_SHA256 = '00:00:00:00:00:00:00:00:00:00:00:00:00' +
+ ':00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00';
+ const ICEUFRAG = 'someufrag';
+ const ICEPWD = 'somelongpwdwithenoughrandomness';
+
+ promise_test(async t => {
+ // audio-only SDP offer without BUNDLE and rtcp-mux.
+ const sdp = 'v=0\r\n' +
+ 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n' +
+ 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
+ 'c=IN IP4 0.0.0.0\r\n' +
+ 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
+ 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
+ 'a=ice-pwd:' + ICEPWD + '\r\n' +
+ 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
+ 'a=setup:actpass\r\n' +
+ 'a=mid:audio1\r\n' +
+ 'a=sendonly\r\n' +
+ 'a=rtcp-rsize\r\n' +
+ 'a=rtpmap:111 opus/48000/2\r\n';
+ const pc = new RTCPeerConnection({rtcpMuxPolicy: 'require'});
+ t.add_cleanup(() => pc.close());
+
+ return promise_rejects_dom(t, 'InvalidAccessError', pc.setRemoteDescription({type: 'offer', sdp}));
+ }, 'setRemoteDescription throws InvalidAccessError when called with an offer without rtcp-mux and rtcpMuxPolicy is set to require');
+
+ promise_test(async t => {
+ // audio-only SDP answer without BUNDLE and rtcp-mux.
+ // Also omitting a=mid in order to avoid parsing it from the offer as this needs to match.
+ const sdp = 'v=0\r\n' +
+ 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n' +
+ 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
+ 'c=IN IP4 0.0.0.0\r\n' +
+ 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
+ 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
+ 'a=ice-pwd:' + ICEPWD + '\r\n' +
+ 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
+ 'a=setup:active\r\n' +
+ 'a=sendonly\r\n' +
+ 'a=rtcp-rsize\r\n' +
+ 'a=rtpmap:111 opus/48000/2\r\n';
+ const pc = new RTCPeerConnection({rtcpMuxPolicy: 'require'});
+ t.add_cleanup(() => pc.close());
+
+ const offer = await generateAudioReceiveOnlyOffer(pc);
+ await pc.setLocalDescription(offer);
+ return promise_rejects_dom(t, 'InvalidAccessError', pc.setRemoteDescription({type: 'answer', sdp}));
+ }, 'setRemoteDescription throws InvalidAccessError when called with an answer without rtcp-mux and rtcpMuxPolicy is set to require');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCDTMFSender.prototype.insertDTMF</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/RTCDTMFSender-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
+ // generateAnswer
+
+ // The following helper functions are called from RTCDTMFSender-helper.js
+ // createDtmfSender
+ // test_tone_change_events
+ // getTransceiver
+
+ /*
+ 7. Peer-to-peer DTMF
+ partial interface RTCRtpSender {
+ readonly attribute RTCDTMFSender? dtmf;
+ };
+
+ interface RTCDTMFSender : EventTarget {
+ void insertDTMF(DOMString tones,
+ optional unsigned long duration = 100,
+ optional unsigned long interToneGap = 70);
+ attribute EventHandler ontonechange;
+ readonly attribute DOMString toneBuffer;
+ };
+ */
+
+ /*
+ 7.2. insertDTMF
+ The tones parameter is treated as a series of characters.
+
+ The characters 0 through 9, A through D, #, and * generate the associated
+ DTMF tones.
+
+ The characters a to d MUST be normalized to uppercase on entry and are
+ equivalent to A to D.
+
+ As noted in [RTCWEB-AUDIO] Section 3, support for the characters 0 through 9,
+ A through D, #, and * are required.
+
+ The character ',' MUST be supported, and indicates a delay of 2 seconds
+ before processing the next character in the tones parameter.
+
+ All other characters (and only those other characters) MUST be considered
+ unrecognized.
+ */
+ promise_test(async t => {
+ const dtmfSender = await createDtmfSender();
+ dtmfSender.insertDTMF('');
+ dtmfSender.insertDTMF('012345689');
+ dtmfSender.insertDTMF('ABCD');
+ dtmfSender.insertDTMF('abcd');
+ dtmfSender.insertDTMF('#*');
+ dtmfSender.insertDTMF(',');
+ dtmfSender.insertDTMF('0123456789ABCDabcd#*,');
+ }, 'insertDTMF() should succeed if tones contains valid DTMF characters');
+
+
+ /*
+ 7.2. insertDTMF
+ 6. If tones contains any unrecognized characters, throw an
+ InvalidCharacterError.
+ */
+ promise_test(async t => {
+ const dtmfSender = await createDtmfSender();
+ assert_throws_dom('InvalidCharacterError', () =>
+ // 'F' is invalid
+ dtmfSender.insertDTMF('123FFABC'));
+
+ assert_throws_dom('InvalidCharacterError', () =>
+ // 'E' is invalid
+ dtmfSender.insertDTMF('E'));
+
+ assert_throws_dom('InvalidCharacterError', () =>
+ // ' ' is invalid
+ dtmfSender.insertDTMF('# *'));
+ }, 'insertDTMF() should throw InvalidCharacterError if tones contains invalid DTMF characters');
+
+ /*
+ 7.2. insertDTMF
+ 3. If transceiver.stopped is true, throw an InvalidStateError.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const dtmfSender = transceiver.sender.dtmf;
+
+ transceiver.stop();
+ assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
+
+ }, 'insertDTMF() should throw InvalidStateError if transceiver is stopped');
+
+ /*
+ 7.2. insertDTMF
+ 4. If transceiver.currentDirection is recvonly or inactive, throw an InvalidStateError.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const transceiver =
+ caller.addTransceiver('audio', { direction: 'recvonly' });
+ const dtmfSender = transceiver.sender.dtmf;
+
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ callee.addTrack(track, stream);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'recvonly');
+ assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
+ }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is recvonly');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver =
+ pc.addTransceiver('audio', { direction: 'inactive' });
+ const dtmfSender = transceiver.sender.dtmf;
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'inactive');
+ assert_throws_dom('InvalidStateError', () => dtmfSender.insertDTMF(''));
+ }, 'insertDTMF() should throw InvalidStateError if transceiver.currentDirection is inactive');
+
+ /*
+ 7.2. insertDTMF
+ The characters a to d MUST be normalized to uppercase on entry and are
+ equivalent to A to D.
+
+ 7. Set the object's toneBuffer attribute to tones.
+ */
+ promise_test(async t => {
+ const dtmfSender = await createDtmfSender();
+ dtmfSender.insertDTMF('123');
+ assert_equals(dtmfSender.toneBuffer, '123');
+
+ dtmfSender.insertDTMF('ABC');
+ assert_equals(dtmfSender.toneBuffer, 'ABC');
+
+ dtmfSender.insertDTMF('bcd');
+ assert_equals(dtmfSender.toneBuffer, 'BCD');
+ }, 'insertDTMF() should set toneBuffer to provided tones normalized, with old tones overridden');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ const sender = pc.addTrack(track, mediaStream);
+ await pc.setLocalDescription(await pc.createOffer());
+ const dtmfSender = sender.dtmf;
+ pc.removeTrack(sender);
+ pc.close();
+ assert_throws_dom('InvalidStateError', () =>
+ dtmfSender.insertDTMF('123'));
+ }, 'insertDTMF() after remove and close should reject');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDTMFSender.prototype.ontonechange (Long Timeout)</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/RTCDTMFSender-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 RTCDTMFSender-helper.js
+ // test_tone_change_events
+
+ /*
+ 7. Peer-to-peer DTMF
+ partial interface RTCRtpSender {
+ readonly attribute RTCDTMFSender? dtmf;
+ };
+
+ interface RTCDTMFSender : EventTarget {
+ void insertDTMF(DOMString tones,
+ optional unsigned long duration = 100,
+ optional unsigned long interToneGap = 70);
+ attribute EventHandler ontonechange;
+ readonly attribute DOMString toneBuffer;
+ };
+
+ [Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
+ interface RTCDTMFToneChangeEvent : Event {
+ readonly attribute DOMString tone;
+ };
+ */
+
+ /*
+ 7.2. insertDTMF
+ 8. If the value of the duration parameter is less than 40, set it to 40.
+ If, on the other hand, the value is greater than 6000, set it to 6000.
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('A', 8000, 70);
+ }, [
+ ['A', '', 0],
+ ['', '', 6070]
+ ],'insertDTMF with duration greater than 6000 should be clamped to 6000');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCDTMFSender.prototype.ontonechange</title>
+<meta name="timeout" content="long">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/RTCDTMFSender-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
+ // generateAnswer
+
+ // The following helper functions are called from RTCDTMFSender-helper.js
+ // test_tone_change_events
+ // getTransceiver
+
+ /*
+ 7. Peer-to-peer DTMF
+ partial interface RTCRtpSender {
+ readonly attribute RTCDTMFSender? dtmf;
+ };
+
+ interface RTCDTMFSender : EventTarget {
+ void insertDTMF(DOMString tones,
+ optional unsigned long duration = 100,
+ optional unsigned long interToneGap = 70);
+ attribute EventHandler ontonechange;
+ readonly attribute DOMString toneBuffer;
+ };
+
+ [Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
+ interface RTCDTMFToneChangeEvent : Event {
+ readonly attribute DOMString tone;
+ };
+ */
+
+ /*
+ 7.2. insertDTMF
+ 11. If a Playout task is scheduled to be run; abort these steps; otherwise queue
+ a task that runs the following steps (Playout task):
+ 3. If toneBuffer is an empty string, fire an event named tonechange with an
+ empty string at the RTCDTMFSender object and abort these steps.
+ 4. Remove the first character from toneBuffer and let that character be tone.
+ 6. Queue a task to be executed in duration + interToneGap ms from now that
+ runs the steps labelled Playout task.
+ 7. Fire an event named tonechange with a string consisting of tone at the
+ RTCDTMFSender object.
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('123');
+ }, [
+ ['1', '23', 0],
+ ['2', '3', 170],
+ ['3', '', 170],
+ ['', '', 170]
+ ], 'insertDTMF() with default duration and intertoneGap should fire tonechange events at the expected time');
+
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('abc', 100, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 170],
+ ['C', '', 170],
+ ['', '', 170]
+ ], 'insertDTMF() with explicit duration and intertoneGap should fire tonechange events at the expected time');
+
+ /*
+ 7.2. insertDTMF
+ 10. If toneBuffer is an empty string, abort these steps.
+ */
+ async_test(t => {
+ createDtmfSender()
+ .then(dtmfSender => {
+ dtmfSender.addEventListener('tonechange',
+ t.unreached_func('Expect no tonechange event to be fired'));
+
+ dtmfSender.insertDTMF('', 100, 70);
+
+ t.step_timeout(t.step_func_done(), 300);
+ })
+ .catch(t.step_func(err => {
+ assert_unreached(`Unexpected promise rejection: ${err}`);
+ }));
+ }, `insertDTMF('') should not fire any tonechange event, including for '' tone`);
+
+ /*
+ 7.2. insertDTMF
+ 8. If the value of the duration parameter is less than 40, set it to 40.
+ If, on the other hand, the value is greater than 6000, set it to 6000.
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('ABC', 10, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 110],
+ ['C', '', 110],
+ ['', '', 110]
+ ], 'insertDTMF() with duration less than 40 should be clamped to 40');
+
+ /*
+ 7.2. insertDTMF
+ 9. If the value of the interToneGap parameter is less than 30, set it to 30.
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('ABC', 100, 10);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 130],
+ ['C', '', 130],
+ ['', '', 130]
+ ],
+ 'insertDTMF() with interToneGap less than 30 should be clamped to 30');
+
+ /*
+ [w3c/webrtc-pc#1373]
+ This step is added to handle the "," character correctly. "," supposed to delay the next
+ tonechange event by 2000ms.
+
+ 7.2. insertDTMF
+ 11.5. If tone is "," delay sending tones for 2000 ms on the associated RTP media
+ stream, and queue a task to be executed in 2000 ms from now that runs the
+ steps labelled Playout task.
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.insertDTMF('A,B', 100, 70);
+
+ }, [
+ ['A', ',B', 0],
+ [',', 'B', 170],
+ ['B', '', 2000],
+ ['', '', 170]
+ ], 'insertDTMF with comma should delay next tonechange event for a constant 2000ms');
+
+ /*
+ 7.2. insertDTMF
+ 11.1. If transceiver.stopped is true, abort these steps.
+ */
+ test_tone_change_events((t, dtmfSender, pc) => {
+ const transceiver = getTransceiver(pc);
+ dtmfSender.addEventListener('tonechange', ev => {
+ if(ev.tone === 'B') {
+ transceiver.stop();
+ }
+ });
+
+ dtmfSender.insertDTMF('ABC', 100, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 170]
+ ], 'insertDTMF() with transceiver stopped in the middle should stop future tonechange events from firing');
+
+ /*
+ 7.2. insertDTMF
+ 3. If a Playout task is scheduled to be run, abort these steps;
+ otherwise queue a task that runs the following steps (Playout task):
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.addEventListener('tonechange', ev => {
+ if(ev.tone === 'B') {
+ dtmfSender.insertDTMF('12', 100, 70);
+ }
+ });
+
+ dtmfSender.insertDTMF('ABC', 100, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 170],
+ ['1', '2', 170],
+ ['2', '', 170],
+ ['', '', 170]
+ ], 'Calling insertDTMF() in the middle of tonechange events should cause future tonechanges to be updated to new tones');
+
+
+ /*
+ 7.2. insertDTMF
+ 3. If a Playout task is scheduled to be run, abort these steps;
+ otherwise queue a task that runs the following steps (Playout task):
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.addEventListener('tonechange', ev => {
+ if(ev.tone === 'B') {
+ dtmfSender.insertDTMF('12', 100, 70);
+ dtmfSender.insertDTMF('34', 100, 70);
+ }
+ });
+
+ dtmfSender.insertDTMF('ABC', 100, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 170],
+ ['3', '4', 170],
+ ['4', '', 170],
+ ['', '', 170]
+ ], 'Calling insertDTMF() multiple times in the middle of tonechange events should cause future tonechanges to be updated the last provided tones');
+
+ /*
+ 7.2. insertDTMF
+ 3. If a Playout task is scheduled to be run, abort these steps;
+ otherwise queue a task that runs the following steps (Playout task):
+ */
+ test_tone_change_events((t, dtmfSender) => {
+ dtmfSender.addEventListener('tonechange', ev => {
+ if(ev.tone === 'B') {
+ dtmfSender.insertDTMF('');
+ }
+ });
+
+ dtmfSender.insertDTMF('ABC', 100, 70);
+ }, [
+ ['A', 'BC', 0],
+ ['B', 'C', 170],
+ ['', '', 170]
+ ], `Calling insertDTMF('') in the middle of tonechange events should stop future tonechange events from firing`);
+
+ /*
+ 7.2. insertDTMF
+ 11.2. If transceiver.currentDirection is recvonly or inactive, abort these steps.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const dtmfSender = await createDtmfSender(pc);
+ const pc2 = pc.otherPc;
+ assert_true(pc2 instanceof RTCPeerConnection,
+ 'Expect pc2 to be a RTCPeerConnection');
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.sender.dtmf, dtmfSender);
+
+ // Since setRemoteDescription happens in parallel with tonechange event,
+ // We use a flag and allow tonechange events to be fired as long as
+ // the promise returned by setRemoteDescription is not yet resolved.
+ let remoteDescriptionIsSet = false;
+
+ // We only do basic tone verification and not check timing here
+ let expectedTones = ['A', 'B', 'C', 'D', ''];
+
+ const firstTone = new Promise(resolve => {
+ const onToneChange = t.step_func(ev => {
+ assert_false(remoteDescriptionIsSet,
+ 'Expect no tonechange event to be fired after currentDirection is changed to recvonly');
+
+ const { tone } = ev;
+ const expectedTone = expectedTones.shift();
+ assert_equals(tone, expectedTone,
+ `Expect fired event.tone to be ${expectedTone}`);
+
+ if(tone === 'A') {
+ resolve();
+ }
+ });
+ dtmfSender.addEventListener('tonechange', onToneChange);
+ });
+
+ dtmfSender.insertDTMF('ABCD', 100, 70);
+ await firstTone;
+
+ // Only change transceiver.direction after the first
+ // tonechange event, to make sure that tonechange is triggered
+ // then stopped
+ transceiver.direction = 'recvonly';
+ await exchangeOfferAnswer(pc, pc2);
+ assert_equals(transceiver.currentDirection, 'inactive');
+ remoteDescriptionIsSet = true;
+
+ await new Promise(resolve => t.step_timeout(resolve, 300));
+ }, `Setting transceiver.currentDirection to recvonly in the middle of tonechange events should stop future tonechange events from firing`);
+
+ /* Section 7.3 - Tone change event */
+ test(t => {
+ let ev = new RTCDTMFToneChangeEvent('tonechange', {'tone': '1'});
+ assert_equals(ev.type, 'tonechange');
+ assert_equals(ev.tone, '1');
+ }, 'Tone change event constructor works');
+
+ test(t => {
+ let ev = new RTCDTMFToneChangeEvent('worngname', {});
+ }, 'Tone change event with unexpected name should not crash');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel.prototype.bufferedAmount</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// createDataChannelPair
+// awaitMessage
+
+/*
+ 6.2. RTCDataChannel
+ interface RTCDataChannel : EventTarget {
+ ...
+ readonly attribute unsigned long bufferedAmount;
+ void send(USVString data);
+ void send(Blob data);
+ void send(ArrayBuffer data);
+ void send(ArrayBufferView data);
+ };
+
+ bufferedAmount
+ The bufferedAmount attribute must return the number of bytes of application
+ data (UTF-8 text and binary data) that have been queued using send() but that,
+ as of the last time the event loop started executing a task, had not yet been
+ transmitted to the network. (This thus includes any text sent during the
+ execution of the current task, regardless of whether the user agent is able
+ to transmit text asynchronously with script execution.) This does not include
+ framing overhead incurred by the protocol, or buffering done by the operating
+ system or network hardware. The value of the [[BufferedAmount]] slot will only
+ increase with each call to the send() method as long as the [[ReadyState]] slot
+ is open; however, the slot does not reset to zero once the channel closes. When
+ the underlying data transport sends data from its queue, the user agent MUST
+ queue a task that reduces [[BufferedAmount]] with the number of bytes that was
+ sent.
+
+
+ [WebMessaging]
+ interface MessageEvent : Event {
+ readonly attribute any data;
+ ...
+ };
+ */
+
+// Simple ASCII encoded string
+const helloString = 'hello';
+// ASCII encoded buffer representation of the string
+const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
+const helloBlob = new Blob([helloBuffer]);
+
+// Unicode string with multiple code units
+const unicodeString = 'äļįä― åĨ―';
+// UTF-8 encoded buffer representation of the string
+const unicodeBuffer = Uint8Array.of(
+ 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c,
+ 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd);
+
+for (const options of [{}, {negotiated: true, id: 0}]) {
+ const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
+
+ /*
+ Ensure .bufferedAmount is 0 initially for both sides.
+ */
+ promise_test(async (t) => {
+ const [dc1, dc2] = await createDataChannelPair(t, options);
+
+ assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
+ assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
+ }, `${mode} bufferedAmount initial value should be 0 for both peers`);
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+
+ string object
+ Let data be the object and increase the bufferedAmount attribute
+ by the number of bytes needed to express data as UTF-8.
+ */
+ promise_test(async (t) => {
+ const [dc1, dc2] = await createDataChannelPair(t, options);
+
+ dc1.send(unicodeString);
+ assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength,
+ 'Expect bufferedAmount to be the byte length of the unicode string');
+
+ await awaitMessage(dc2);
+ assert_equals(dc1.bufferedAmount, 0,
+ 'Expect sender bufferedAmount to be reduced after message is sent');
+ }, `${mode} bufferedAmount should increase to byte length of encoded` +
+ `unicode string sent`);
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+ ArrayBuffer object
+ Let data be the data stored in the buffer described by the ArrayBuffer
+ object and increase the bufferedAmount attribute by the length of the
+ ArrayBuffer in bytes.
+ */
+ promise_test(async (t) => {
+ const [dc1, dc2] = await createDataChannelPair(t, options);
+
+ dc1.send(helloBuffer.buffer);
+ assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
+ 'Expect bufferedAmount to increase to byte length of sent buffer');
+
+ await awaitMessage(dc2);
+ assert_equals(dc1.bufferedAmount, 0,
+ 'Expect sender bufferedAmount to be reduced after message is sent');
+ }, `${mode} bufferedAmount should increase to byte length of buffer sent`);
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+ Blob object
+ Let data be the raw data represented by the Blob object and increase
+ the bufferedAmount attribute by the size of data, in bytes.
+ */
+
+ promise_test(async (t) => {
+ const [dc1] = await createDataChannelPair(t, options);
+
+ dc1.send(helloBuffer.buffer);
+ assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
+ 'Expect bufferedAmount to increase to byte length of sent buffer');
+
+ dc1.close();
+ assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
+ 'Expect bufferedAmount to not decrease immediately after closing the channel');
+ }, `${mode} bufferedAmount should not decrease immediately after initiating closure`);
+
+ promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const [dc1] = await createDataChannelPair(t, options, pc1);
+
+ dc1.send(helloBuffer.buffer);
+ assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
+ 'Expect bufferedAmount to increase to byte length of sent buffer');
+
+ pc1.close();
+ assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
+ 'Expect bufferedAmount to not decrease after closing the peer connection');
+ }, `${mode} bufferedAmount should not decrease after closing the peer connection`);
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ channel1.addEventListener('bufferedamountlow', t.step_func_done(() => {
+ assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
+ }));
+ const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
+ channel1.send(helloString);
+ await eventWatcher.wait_for(['bufferedamountlow']);
+ }, `${mode} bufferedamountlow event fires after send() is complete`);
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ await awaitMessage(channel2);
+ assert_equals(channel1.bufferedAmount, 0);
+ }, `${mode} bufferedamount is data.length on send(data)`);
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ }, `${mode} bufferedamount returns the same amount if no more data is`);
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ let eventFireCount = 0;
+ channel1.addEventListener('bufferedamountlow', t.step_func(() => {
+ assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
+ assert_equals(++eventFireCount, 1);
+ }));
+ const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, 2 * helloString.length);
+ await eventWatcher.wait_for(['bufferedamountlow']);
+ }, `${mode} bufferedamountlow event fires only once after multiple` +
+ ` consecutive send() calls`);
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ await eventWatcher.wait_for(['bufferedamountlow']);
+ assert_equals(await awaitMessage(channel2), helloString);
+ channel1.send(helloString);
+ assert_equals(channel1.bufferedAmount, helloString.length);
+ await eventWatcher.wait_for(['bufferedamountlow']);
+ assert_equals(await awaitMessage(channel2), helloString);
+ }, `${mode} bufferedamountlow event fires after each sent message`);
+}
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel.prototype.close</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+for (const options of [{}, {negotiated: true, id: 0}]) {
+ const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
+
+ promise_test(async t => {
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ const haveClosed = new Promise(r => channel2.onclose = r);
+ let closingSeen = false;
+ channel1.onclosing = t.unreached_func();
+ channel2.onclosing = () => {
+ assert_equals(channel2.readyState, 'closing');
+ closingSeen = true;
+ };
+ channel2.addEventListener('error', t.unreached_func());
+ channel1.close();
+ await haveClosed;
+ assert_equals(channel2.readyState, 'closed');
+ assert_true(closingSeen, 'Closing event was seen');
+ }, `Close ${mode} causes onclosing and onclose to be called`);
+
+ promise_test(async t => {
+ // This is the same test as above, but using addEventListener
+ // rather than the "onclose" attribute.
+ const [channel1, channel2] = await createDataChannelPair(t, options);
+ const haveClosed = new Promise(r => channel2.addEventListener('close', r));
+ let closingSeen = false;
+ channel1.addEventListener('closing', t.unreached_func());
+ channel2.addEventListener('closing', () => {
+ assert_equals(channel2.readyState, 'closing');
+ closingSeen = true;
+ });
+ channel2.addEventListener('error', t.unreached_func());
+ channel1.close();
+ await haveClosed;
+ assert_equals(channel2.readyState, 'closed');
+ assert_true(closingSeen, 'Closing event was seen');
+ }, `Close ${mode} causes closing and close event to be called`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const [channel1, channel2] = await createDataChannelPair(t, options, pc1);
+ const events = [];
+ let error = null;
+ channel2.addEventListener('error', t.step_func(event => {
+ events.push('error');
+ assert_true(event instanceof RTCErrorEvent);
+ error = event.error;
+ }));
+ const haveClosed = new Promise(r => channel2.addEventListener('close', () => {
+ events.push('close');
+ r();
+ }));
+ pc1.close();
+ await haveClosed;
+ // Error should fire before close.
+ assert_array_equals(events, ['error', 'close']);
+ assert_true(error instanceof RTCError);
+ assert_equals(error.name, 'OperationError');
+ assert_equals(error.errorDetail, 'sctp-failure');
+ // Expects the sctpErrorCode is either null or 12 (User-Initiated Abort) as it is
+ // optional in the SCTP specification.
+ assert_in_array(error.sctpCauseCode, [null, 12]);
+ }, `Close peerconnection causes close event and error to be called on ${mode}`);
+
+ promise_test(async t => {
+ let pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ let [channel1, channel2] = await createDataChannelPair(t, options, pc1);
+ // The expected sequence of events when closing a DC is that
+ // channel1 goes to closing, channel2 fires onclose, and when
+ // the close is confirmed, channel1 fires onclose.
+ // After that, no more events should fire.
+ channel1.onerror = t.unreached_func();
+ let close2Handler = new Promise(resolve => {
+ channel2.onclose = event => {
+ resolve();
+ };
+ });
+ let close1Handler = new Promise(resolve => {
+ channel1.onclose = event => {
+ resolve();
+ };
+ });
+ channel1.close();
+ await close2Handler;
+ await close1Handler;
+ channel1.onclose = t.unreached_func();
+ channel2.onclose = t.unreached_func();
+ channel2.onerror = t.unreached_func();
+ pc1.close();
+ await new Promise(resolve => t.step_timeout(resolve, 10));
+ }, `Close peerconnection after ${mode} close causes no events`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('not-counted', options);
+ const tokenDataChannel = new Promise(resolve => {
+ pc2.ondatachannel = resolve;
+ });
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ if (!options.negotiated) {
+ await tokenDataChannel;
+ }
+ let closeExpectedCount = 0;
+ let errorExpectedCount = 0;
+ let resolveCountIsZero;
+ let waitForCountIsZero = new Promise(resolve => {
+ resolveCountIsZero = resolve;
+ });
+ for (let i = 1; i <= 10; i++) {
+ if ('id' in options) {
+ options.id = i;
+ }
+ pc1.createDataChannel('', options);
+ if (options.negotiated) {
+ const channel = pc2.createDataChannel('', options);
+ channel.addEventListener('error', t.step_func(event => {
+ assert_true(event instanceof RTCErrorEvent, 'error event ' + event);
+ errorExpectedCount -= 1;
+ }));
+ channel.addEventListener('close', t.step_func(event => {
+ closeExpectedCount -= 1;
+ if (closeExpectedCount == 0) {
+ resolveCountIsZero();
+ }
+ }));
+ } else {
+ await new Promise(resolve => {
+ pc2.ondatachannel = ({channel}) => {
+ channel.addEventListener('error', t.step_func(event => {
+ assert_true(event instanceof RTCErrorEvent);
+ errorExpectedCount -= 1;
+ }));
+ channel.addEventListener('close', t.step_func(event => {
+ closeExpectedCount -= 1;
+ if (closeExpectedCount == 0) {
+ resolveCountIsZero();
+ }
+ }));
+ resolve();
+ }
+ });
+ }
+ ++closeExpectedCount;
+ ++errorExpectedCount;
+ }
+ assert_equals(closeExpectedCount, 10);
+ // We have to wait until SCTP is connected before we close, otherwise
+ // there will be no signal.
+ // The state is not available under Plan B, and unreliable on negotiated
+ // channels.
+ // TODO(bugs.webrtc.org/12259): Remove dependency on "negotiated"
+ if (pc1.sctp && !options.negotiated) {
+ waitForState(pc1.sctp, 'connected');
+ } else {
+ // Under plan B, we don't have a dtls transport to wait on, so just
+ // wait a bit.
+ await new Promise(resolve => t.step_timeout(resolve, 100));
+ }
+ pc1.close();
+ await waitForCountIsZero;
+ assert_equals(closeExpectedCount, 0);
+ assert_equals(errorExpectedCount, 0);
+ }, `Close peerconnection causes close event and error on many channels, ${mode}`);
+}
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel interactions with ICE restart</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+async function checkCanPassData(channel1, channel2) {
+ channel1.send('hello');
+ const message = await awaitMessage(channel2);
+ assert_equals(message, 'hello');
+}
+
+async function pingPongData(channel1, channel2, size=1) {
+ channel1.send('hello');
+ const request = await awaitMessage(channel2);
+ assert_equals(request, 'hello');
+ const response = 'x'.repeat(size);
+ channel2.send(response);
+ const responseReceived = await awaitMessage(channel1);
+ assert_equals(response, responseReceived);
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const [channel1, channel2] = await createDataChannelPair(t, {}, pc1, pc2);
+ channel2.addEventListener('error', t.unreached_func());
+ channel2.addEventListener('error', t.unreached_func());
+
+ await checkCanPassData(channel1, channel2);
+ await checkCanPassData(channel2, channel1);
+
+ pc1.restartIce();
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await checkCanPassData(channel1, channel2);
+ await checkCanPassData(channel2, channel1);
+ channel1.close();
+ channel2.close();
+}, `Data channel remains usable after ICE restart`);
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const [channel1, channel2] = await createDataChannelPair(t, {}, pc1, pc2);
+ channel2.addEventListener('error', t.unreached_func());
+ channel2.addEventListener('error', t.unreached_func());
+
+ await pingPongData(channel1, channel2);
+ pc1.restartIce();
+
+ await pc1.setLocalDescription();
+ await pingPongData(channel1, channel2);
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pingPongData(channel1, channel2);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pingPongData(channel1, channel2);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ await pingPongData(channel1, channel2);
+ channel1.close();
+ channel2.close();
+}, `Data channel remains usable at each step of an ICE restart`);
+
+
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCDataChannel id attribute</title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+// This is the maximum number of streams, NOT the maximum stream ID (which is 65534)
+// See: https://tools.ietf.org/html/draft-ietf-rtcweb-data-channel-13#section-6.2
+const nStreams = 65535;
+
+/*
+ 6.1.
+ 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
+ createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
+ transport has already been negotiated, then initialize [[DataChannelId]] to a value
+ generated by the user agent, according to [RTCWEB-DATA-PROTOCOL] [...]
+ */
+promise_test(async (t) => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc1 = pc.createDataChannel('');
+ const ids = new UniqueSet();
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ // Turn our own offer SDP into valid answer SDP by setting the DTLS role to
+ // "active".
+ const answer = {
+ type: 'answer',
+ sdp: pc.localDescription.sdp.replace('actpass', 'active')
+ };
+ await pc.setRemoteDescription(answer);
+
+ // Since the remote description had an 'active' DTLS role, we're the server
+ // and should use odd data channel IDs, according to rtcweb-data-channel.
+ assert_equals(dc1.id % 2, 1,
+ `Channel created by the DTLS server role must be odd (was ${dc1.id})`);
+ const dc2 = pc.createDataChannel('another');
+ assert_equals(dc2.id % 2, 1,
+ `Channel created by the DTLS server role must be odd (was ${dc2.id})`);
+
+ // Ensure IDs are unique
+ ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
+ ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
+}, 'DTLS client uses odd data channel IDs');
+
+promise_test(async (t) => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc1 = pc.createDataChannel('');
+ const ids = new UniqueSet();
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ // Turn our own offer SDP into valid answer SDP by setting the DTLS role to
+ // 'passive'.
+ const answer = {
+ type: 'answer',
+ sdp: pc.localDescription.sdp.replace('actpass', 'passive')
+ };
+ await pc.setRemoteDescription(answer);
+
+ // Since the remote description had a 'passive' DTLS role, we're the client
+ // and should use even data channel IDs, according to rtcweb-data-channel.
+ assert_equals(dc1.id % 2, 0,
+ `Channel created by the DTLS client role must be even (was ${dc1.id})`);
+ const dc2 = pc.createDataChannel('another');
+ assert_equals(dc2.id % 2, 0,
+ `Channel created by the DTLS client role must be even (was ${dc1.id})`);
+
+ // Ensure IDs are unique
+ ids.add(dc1.id, `Channel ID ${dc1.id} should be unique`);
+ ids.add(dc2.id, `Channel ID ${dc2.id} should be unique`);
+}, 'DTLS server uses even data channel IDs');
+
+/*
+ Checks that the id is ignored if "negotiated" is false.
+ See section 6.1, createDataChannel step 13.
+ */
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel('', {
+ negotiated: false,
+ id: 42
+ });
+ dc1.onopen = t.step_func(() => {
+ dc1.send(':(');
+ });
+
+ const dc2 = pc2.createDataChannel('', {
+ negotiated: false,
+ id: 42
+ });
+ // ID should be null prior to negotiation.
+ assert_equals(dc1.id, null);
+ assert_equals(dc2.id, null);
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ // We should now have 2 datachannels with different IDs.
+ // At least one of the datachannels should not be 42.
+ // If one has the value 42, it's an accident; if both have,
+ // they are the same datachannel, and it's a bug.
+ assert_false(dc1.id == 42 && dc2.id == 42);
+}, 'In-band negotiation with a specific ID should not work');
+
+/*
+ Check if the implementation still follows the odd/even role correctly if we annoy it with
+ negotiated channels not following that rule.
+
+ Note: This test assumes that the implementation can handle a minimum of 40 data channels.
+ */
+promise_test(async (t) => {
+ // Takes the DTLS server role
+ const pc1 = new RTCPeerConnection();
+ // Takes the DTLS client role
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ exchangeIceCandidates(pc1, pc2);
+ const dcs = [];
+ const negotiatedDcs = [];
+ const ids = new UniqueSet();
+
+ // Create 10 DCEP-negotiated channels with pc1
+ // Note: These should not have any associated valid ID at this point
+ for (let i = 0; i < 10; ++i) {
+ const dc = pc1.createDataChannel('before-connection');
+ assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
+ dcs.push(dc);
+ }
+
+ // Create 10 negotiated channels with pc1 violating the odd/even rule
+ for (let id = 0; id < 20; id += 2) {
+ const dc = pc1.createDataChannel(`negotiated-not-odd-${id}-before-connection`, {
+ negotiated: true,
+ id: id,
+ });
+ assert_equals(dc.id, id, 'Channel id must be set before DTLS role has been determined when negotiated is true');
+ negotiatedDcs.push([dc, id]);
+ ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
+ }
+
+ await exchangeOfferAnswer(pc1, pc2, {
+ offer: (offer) => {
+ // Ensure pc1 takes the server role
+ assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
+ 'pc1 must take the DTLS server role');
+ return offer;
+ },
+ answer: (answer) => {
+ // Ensure pc2 takes the client role
+ // Note: It very likely will choose 'active' itself
+ answer.sdp = answer.sdp.replace('actpass', 'active');
+ assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
+ return answer;
+ },
+ });
+
+ for (const dc of dcs) {
+ assert_equals(dc.id % 2, 1,
+ `Channel created by the DTLS server role must be odd (was ${dc.id})`);
+ ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
+ }
+
+ // Create 10 channels with pc1
+ for (let i = 0; i < 10; ++i) {
+ const dc = pc1.createDataChannel('after-connection');
+ assert_equals(dc.id % 2, 1,
+ `Channel created by the DTLS server role must be odd (was ${dc.id})`);
+ dcs.push(dc);
+ ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
+ }
+
+ // Create 10 negotiated channels with pc1 violating the odd/even rule
+ for (let i = 0; i < 10; ++i) {
+ // Generate a valid even ID that has not been taken, yet.
+ let id = 20;
+ while (ids.has(id)) {
+ id += 2;
+ }
+ const dc = pc1.createDataChannel(`negotiated-not-odd-${i}-after-connection`, {
+ negotiated: true,
+ id: id,
+ });
+ negotiatedDcs.push([dc, id]);
+ ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
+ }
+
+ // Since we've added new channels, let's check again that the odd/even role is not violated
+ for (const dc of dcs) {
+ assert_equals(dc.id % 2, 1,
+ `Channel created by the DTLS server role must be odd (was ${dc.id})`);
+ }
+
+ // Let's also make sure the negotiated channels have kept their ID
+ for (const [dc, id] of negotiatedDcs) {
+ assert_equals(dc.id, id, 'Negotiated channels should keep their assigned ID');
+ }
+}, 'Odd/even role should not be violated when mixing with negotiated channels');
+
+/*
+ Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted AFTER
+ establishing a peer connection.
+
+ 6.1. createDataChannel
+ 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
+ createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
+ transport has already been negotiated, then initialize [[DataChannelId]] to a value
+ generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
+ to the next step. If no available ID could be generated, or if the value of the
+ [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
+ OperationError exception.
+ */
+/*
+ TODO: Improve test coverage for RTCSctpTransport.maxChannels.
+ TODO: Improve test coverage for exhausting channel cases.
+ */
+
+/*
+ Create 32768 (client), 32767 (server) channels to make sure all ids are exhausted BEFORE
+ establishing a peer connection.
+
+ Be aware that late channel id assignment can currently fail in many places not covered by the
+ spec, see: https://github.com/w3c/webrtc-pc/issues/1818
+
+ 4.4.1.6.
+ 2.2.6. If description negotiates the DTLS role of the SCTP transport, and there is an
+ RTCDataChannel with a null id, then generate an ID according to [RTCWEB-DATA-PROTOCOL].
+ If no available ID could be generated, then run the following steps:
+ 1. Let channel be the RTCDataChannel object for which an ID could not be generated.
+ 2. Set channel's [[ReadyState]] slot to "closed".
+ 3. Fire an event named error with an OperationError exception at channel.
+ 4. Fire a simple event named close at channel.
+ */
+/* TEST DISABLED - it takes so long, it times out.
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ // Takes the DTLS server role
+ const pc1 = new RTCPeerConnection();
+ // Takes the DTLS client role
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ exchangeIceCandidates(pc1, pc2);
+ const dcs = [];
+ const ids = new UniqueSet();
+ let nExpected = 0;
+ let nActualCloses = 0;
+ let nActualErrors = 0;
+
+ const maybeDone = t.step_func(() => {
+ if (nExpected === nActualCloses && nExpected === nActualErrors) {
+ resolver.resolve();
+ }
+ });
+
+ // Create 65535+2 channels (since 65535 streams is a SHOULD, we may have less than that.)
+ // Create two extra channels to possibly trigger the steps in the description.
+ //
+ // Note: Following the spec strictly would assume that this cannot fail. But in reality it will
+ // fail because the implementation knows how many streams it supports. What it doesn't
+ // know is how many streams the other peer supports (e.g. what will be negotiated).
+ for (let i = 0; i < (nStreams + 2); ++i) {
+ let dc;
+ try {
+ const pc = i % 2 === 1 ? pc1 : pc2;
+ dc = pc.createDataChannel('this is going to be fun');
+ dc.onclose = t.step_func(() => {
+ ++nActualCloses;
+ maybeDone();
+ });
+ dc.onerror = t.step_func((e) => {
+ assert_true(e instanceof RTCError, 'Expect error object to be instance of RTCError');
+ assert_equals(e.error, 'sctp-failure', "Expect error to be of type 'sctp-failure'");
+ ++nActualErrors;
+ maybeDone();
+ });
+ } catch (e) {
+ assert_equals(e.name, 'OperationError', 'Fail on creation should throw OperationError');
+ break;
+ }
+ assert_equals(dc.id, null, 'Channel id must be null before DTLS role has been determined');
+ assert_not_equals(dc.readyState, 'closed',
+ 'Channel may not be closed before connection establishment');
+ dcs.push([dc, i % 2 === 1]);
+ }
+
+ await exchangeOfferAnswer(pc1, pc2, {
+ offer: (offer) => {
+ // Ensure pc1 takes the server role
+ assert_true(offer.sdp.includes('actpass') || offer.sdp.includes('passive'),
+ 'pc1 must take the DTLS server role');
+ return offer;
+ },
+ answer: (answer) => {
+ // Ensure pc2 takes the client role
+ // Note: It very likely will choose 'active' itself
+ answer.sdp = answer.sdp.replace('actpass', 'active');
+ assert_true(answer.sdp.includes('active'), 'pc2 must take the DTLS client role');
+ return answer;
+ },
+ });
+
+ // Since the spec does not define a specific order to which channels may fail if an ID could
+ // not be generated, any of the channels may be affected by the steps of the description.
+ for (const [dc, odd] of dcs) {
+ if (dc.readyState !== 'closed') {
+ assert_equals(dc.id % 2, odd ? 1 : 0,
+ `Channels created by the DTLS ${odd ? 'server' : 'client'} role must be
+ ${odd ? 'odd' : 'even'} (was ${dc.id})`);
+ ids.add(dc.id, `Channel ID ${dc.id} should be unique`);
+ } else {
+ ++nExpected;
+ }
+ }
+
+ // Try creating one further channel on both sides. The attempt should fail since all IDs are
+ // taken. If one ID is available, the implementation probably miscounts (or I did in the test).
+ assert_throws_dom('OperationError', () =>
+ pc1.createDataChannel('this is too exhausting!'));
+ assert_throws_dom('OperationError', () =>
+ pc2.createDataChannel('this is too exhausting!'));
+
+ maybeDone();
+ await resolver;
+}, 'Channel ID exhaustion handling (before and after connection establishment)');
+
+END DISABLED TEST */
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCDataChannel.prototype.send</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+// createDataChannelPair
+// awaitMessage
+// blobToArrayBuffer
+// assert_equals_typed_array
+
+/*
+ 6.2. RTCDataChannel
+ interface RTCDataChannel : EventTarget {
+ ...
+ readonly attribute RTCDataChannelState readyState;
+ readonly attribute unsigned long bufferedAmount;
+ attribute EventHandler onmessage;
+ attribute DOMString binaryType;
+
+ void send(USVString data);
+ void send(Blob data);
+ void send(ArrayBuffer data);
+ void send(ArrayBufferView data);
+ };
+ */
+
+// Simple ASCII encoded string
+const helloString = 'hello';
+const emptyString = '';
+// ASCII encoded buffer representation of the string
+const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
+const emptyBuffer = new Uint8Array();
+const helloBlob = new Blob([helloBuffer]);
+
+// Unicode string with multiple code units
+const unicodeString = 'äļįä― åĨ―';
+// UTF-8 encoded buffer representation of the string
+const unicodeBuffer = Uint8Array.of(
+ 0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c,
+ 0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd);
+
+/*
+ 6.2. send()
+ 2. If channel's readyState attribute is connecting, throw an InvalidStateError.
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ const channel = pc.createDataChannel('test');
+ assert_equals(channel.readyState, 'connecting');
+ assert_throws_dom('InvalidStateError', () => channel.send(helloString));
+}, 'Calling send() when data channel is in connecting state should throw InvalidStateError');
+
+for (const options of [{}, {negotiated: true, id: 0}]) {
+ const mode = `${options.negotiated? "Negotiated d" : "D"}atachannel`;
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+
+ string object
+ Let data be the object and increase the bufferedAmount attribute
+ by the number of bytes needed to express data as UTF-8.
+
+ [WebSocket]
+ 5. Feedback from the protocol
+ When a WebSocket message has been received
+ 4. If type indicates that the data is Text, then initialize event's data
+ attribute to data.
+ */
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel1.send(helloString);
+ return awaitMessage(channel2)
+ }).then(message => {
+ assert_equals(typeof message, 'string',
+ 'Expect message to be a string');
+
+ assert_equals(message, helloString);
+ });
+ }, `${mode} should be able to send simple string and receive as string`);
+
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel1.send(unicodeString);
+ return awaitMessage(channel2)
+ }).then(message => {
+ assert_equals(typeof message, 'string',
+ 'Expect message to be a string');
+
+ assert_equals(message, unicodeString);
+ });
+ }, `${mode} should be able to send unicode string and receive as unicode string`);
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel2.binaryType = 'arraybuffer';
+ channel1.send(helloString);
+ return awaitMessage(channel2);
+ }).then(message => {
+ assert_equals(typeof message, 'string',
+ 'Expect message to be a string');
+
+ assert_equals(message, helloString);
+ });
+ }, `${mode} should ignore binaryType and always receive string message as string`);
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel1.send(emptyString);
+ // Send a non-empty string in case the implementation ignores empty messages
+ channel1.send(helloString);
+ return awaitMessage(channel2)
+ }).then(message => {
+ assert_equals(typeof message, 'string',
+ 'Expect message to be a string');
+
+ assert_equals(message, emptyString);
+ });
+ }, `${mode} should be able to send an empty string and receive an empty string`);
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+ ArrayBufferView object
+ Let data be the data stored in the section of the buffer described
+ by the ArrayBuffer object that the ArrayBufferView object references
+ and increase the bufferedAmount attribute by the length of the
+ ArrayBufferView in bytes.
+
+ [WebSocket]
+ 5. Feedback from the protocol
+ When a WebSocket message has been received
+ 4. If binaryType is set to "arraybuffer", then initialize event's data
+ attribute to a new read-only ArrayBuffer object whose contents are data.
+
+ [WebIDL]
+ 4.1. ArrayBufferView
+ typedef (Int8Array or Int16Array or Int32Array or
+ Uint8Array or Uint16Array or Uint32Array or Uint8ClampedArray or
+ Float32Array or Float64Array or DataView) ArrayBufferView;
+ */
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel2.binaryType = 'arraybuffer';
+ channel1.send(helloBuffer);
+ return awaitMessage(channel2)
+ }).then(messageBuffer => {
+ assert_true(messageBuffer instanceof ArrayBuffer,
+ 'Expect messageBuffer to be an ArrayBuffer');
+
+ assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
+ });
+ }, `${mode} should be able to send Uint8Array message and receive as ArrayBuffer`);
+
+ /*
+ 6.2. send()
+ 3. Execute the sub step that corresponds to the type of the methods argument:
+ ArrayBuffer object
+ Let data be the data stored in the buffer described by the ArrayBuffer
+ object and increase the bufferedAmount attribute by the length of the
+ ArrayBuffer in bytes.
+ */
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel2.binaryType = 'arraybuffer';
+ channel1.send(helloBuffer.buffer);
+ return awaitMessage(channel2)
+ }).then(messageBuffer => {
+ assert_true(messageBuffer instanceof ArrayBuffer,
+ 'Expect messageBuffer to be an ArrayBuffer');
+
+ assert_equals_typed_array(messageBuffer, helloBuffer.buffer);
+ });
+ }, `${mode} should be able to send ArrayBuffer message and receive as ArrayBuffer`);
+
+ promise_test(t => {
+ return createDataChannelPair(t, options)
+ .then(([channel1, channel2]) => {
+ channel2.binaryType = 'arraybuffer';
+ channel1.send(emptyBuffer.buffer);
+ // Send a non-empty buffer in case the implementation ignores empty messages
+ channel1.send(helloBuffer.buffer);
+ return awaitMessage(channel2)
+ }).then(messageBuffer => {
+ assert_true(messageBuffer instanceof ArrayBuffer,
+ 'Expect messageBuffer to be an ArrayBuffer');
+
+ assert_equals_typed_array(messageBuffer, emptyBuffer.buffer);
+ });
+ }, `${mode} should be able to send an empty ArrayBuffer message and receive as ArrayBuffer`);
+
+}
+</script>
--- /dev/null
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>RTCDataChannelEvent constructor</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+test(function() {
+ assert_equals(RTCDataChannelEvent.length, 2);
+ assert_throws_js(
+ TypeError,
+ function() { new RTCDataChannelEvent('type'); }
+ );
+}, 'RTCDataChannelEvent constructor without a required argument.');
+
+test(function() {
+ assert_throws_js(
+ TypeError,
+ function() { new RTCDataChannelEvent('type', { channel: null }); }
+ );
+}, 'RTCDataChannelEvent constructor with channel passed as null.');
+
+test(function() {
+ assert_throws_js(
+ TypeError,
+ function() { new RTCDataChannelEvent('type', { channel: undefined }); }
+ );
+}, 'RTCDataChannelEvent constructor with a channel passed as undefined.');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('');
+ const event = new RTCDataChannelEvent('type', { channel: dc });
+ assert_true(event instanceof RTCDataChannelEvent);
+ assert_equals(event.channel, dc);
+}, 'RTCDataChannelEvent constructor with full arguments.');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCDtlsTransport.prototype.getRemoteCertificates</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // exchangeIceCandidates
+ // exchangeOfferAnswer
+
+ /*
+ 5.5. RTCDtlsTransport Interface
+ interface RTCDtlsTransport : EventTarget {
+ readonly attribute RTCDtlsTransportState state;
+ sequence<ArrayBuffer> getRemoteCertificates();
+ attribute EventHandler onstatechange;
+ attribute EventHandler onerror;
+ ...
+ };
+
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+ getRemoteCertificates
+ Returns the certificate chain in use by the remote side, with each certificate
+ encoded in binary Distinguished Encoding Rules (DER) [X690].
+ getRemoteCertificates() will return an empty list prior to selection of the
+ remote certificate, which will be completed by the time RTCDtlsTransportState
+ transitions to "connected".
+ */
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(trackFactories.audio());
+ exchangeIceCandidates(pc1, pc2);
+
+ exchangeOfferAnswer(pc1, pc2)
+ .then(t.step_func(() => {
+ const dtlsTransport1 = pc1.getSenders()[0].transport;
+ const dtlsTransport2 = pc2.getReceivers()[0].transport;
+
+ const testedTransports = new Set();
+
+ // Callback function that test the respective DTLS transports
+ // when they become connected.
+ const onConnected = t.step_func(dtlsTransport => {
+ const certs = dtlsTransport.getRemoteCertificates();
+
+ assert_greater_than(certs.length, 0,
+ 'Expect DTLS transport to have at least one remote certificate when connected');
+
+ for(const cert of certs) {
+ assert_true(cert instanceof ArrayBuffer,
+ 'Expect certificate elements be instance of ArrayBuffer');
+ }
+
+ testedTransports.add(dtlsTransport);
+
+ // End the test if both dtlsTransports are tested.
+ if(testedTransports.has(dtlsTransport1) && testedTransports.has(dtlsTransport2)) {
+ t.done();
+ }
+ })
+
+ for(const dtlsTransport of [dtlsTransport1, dtlsTransport2]) {
+ if(dtlsTransport.state === 'connected') {
+ onConnected(dtlsTransport);
+ } else {
+ assert_array_equals(dtlsTransport.getRemoteCertificates(), [],
+ 'Expect DTLS certificates be initially empty until become connected');
+
+ dtlsTransport.addEventListener('statechange', t.step_func(() => {
+ if(dtlsTransport.state === 'connected') {
+ onConnected(dtlsTransport);
+ }
+ }));
+
+ dtlsTransport.addEventListener('error', t.step_func(err => {
+ assert_unreached(`Unexpected error during DTLS handshake: ${err}`);
+ }));
+ }
+ }
+ }));
+ });
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCDtlsTransport</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// exchangeIceCandidates
+// exchangeOfferAnswer
+// trackFactories.audio()
+
+/*
+ 5.5. RTCDtlsTransport Interface
+ interface RTCDtlsTransport : EventTarget {
+ readonly attribute RTCDtlsTransportState state;
+ sequence<ArrayBuffer> getRemoteCertificates();
+ attribute EventHandler onstatechange;
+ attribute EventHandler onerror;
+ ...
+ };
+
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+*/
+function resolveWhen(t, dtlstransport, state) {
+ return new Promise((resolve, reject) => {
+ if (dtlstransport.state == state) { resolve(); }
+ dtlstransport.addEventListener('statechange', t.step_func(e => {
+ if (dtlstransport.state == state) {
+ resolve();
+ }
+ }));
+ });
+}
+
+
+async function setupConnections(t) {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(trackFactories.audio());
+ const channels = exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ return [pc1, pc2];
+}
+
+promise_test(async t => {
+ const [pc1, pc2] = await setupConnections(t);
+ const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
+ const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
+ assert_true(dtlsTransport1 instanceof RTCDtlsTransport);
+ assert_true(dtlsTransport2 instanceof RTCDtlsTransport);
+ await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
+ resolveWhen(t, dtlsTransport2, 'connected')]);
+}, 'DTLS transport goes to connected state');
+
+promise_test(async t => {
+ const [pc1, pc2] = await setupConnections(t);
+
+ const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
+ const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
+ await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
+ resolveWhen(t, dtlsTransport2, 'connected')]);
+ pc1.close();
+ assert_equals(dtlsTransport1.state, 'closed');
+}, 'close() causes the local transport to close immediately');
+
+promise_test(async t => {
+ const [pc1, pc2] = await setupConnections(t);
+ const dtlsTransport1 = pc1.getTransceivers()[0].sender.transport;
+ const dtlsTransport2 = pc2.getTransceivers()[0].sender.transport;
+ await Promise.all([resolveWhen(t, dtlsTransport1, 'connected'),
+ resolveWhen(t, dtlsTransport2, 'connected')]);
+ pc1.close();
+ await resolveWhen(t, dtlsTransport2, 'closed');
+}, 'close() causes the other end\'s DTLS transport to close');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCError and RTCErrorInit</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_equals(error.message, 'message');
+ assert_equals(error.errorDetail, 'data-channel-failure');
+}, 'RTCError constructor with errorDetail and message');
+
+test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'});
+ assert_equals(error.message, '');
+}, 'RTCError constructor\'s message argument is optional');
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new RTCError();
+ });
+ assert_throws_js(TypeError, () => {
+ new RTCError({}); // {errorDetail} is missing.
+ });
+}, 'RTCError constructor throws TypeError if arguments are missing');
+
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new RTCError({errorDetail:'invalid-error-detail'}, 'message');
+ });
+}, 'RTCError constructor throws TypeError if the errorDetail is invalid');
+
+test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_equals(error.name, 'OperationError');
+}, 'RTCError.name is \'OperationError\'');
+
+test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_equals(error.code, 0);
+}, 'RTCError.code is 0');
+
+test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_throws_js(TypeError, () => {
+ error.errorDetail = 'dtls-failure';
+ });
+}, 'RTCError.errorDetail is readonly.');
+
+test(() => {
+ // Infers what are valid RTCErrorInit objects by passing them to the RTCError
+ // constructor.
+ assert_throws_js(TypeError, () => {
+ new RTCError({}, 'message');
+ });
+ new RTCError({errorDetail:'data-channel-failure'}, 'message');
+}, 'RTCErrorInit.errorDetail is the only required attribute');
+
+// All of these are number types (long or unsigned long).
+const nullableAttributes = ['sdpLineNumber',
+ 'httpRequestStatusCode',
+ 'sctpCauseCode',
+ 'receivedAlert',
+ 'sentAlert'];
+
+nullableAttributes.forEach(attribute => {
+ test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_equals(error[attribute], null);
+ }, 'RTCError.' + attribute + ' is null by default');
+
+ test(() => {
+ const error = new RTCError(
+ {errorDetail:'data-channel-failure', [attribute]: 0}, 'message');
+ assert_equals(error[attribute], 0);
+ }, 'RTCError.' + attribute + ' is settable by constructor');
+
+ test(() => {
+ const error = new RTCError({errorDetail:'data-channel-failure'}, 'message');
+ assert_throws_js(TypeError, () => {
+ error[attribute] = 42;
+ });
+ }, 'RTCError.' + attribute + ' is readonly');
+});
+
+</script>
--- /dev/null
+<!doctype html>
+<title>RTCIceCandidate constructor</title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+ 'use strict';
+
+ const candidateString = 'candidate:1905690388 1 udp 2113937151 192.168.0.1 58041 typ host generation 0 ufrag thC8 network-cost 50';
+ const candidateString2 = 'candidate:435653019 2 tcp 1845501695 192.168.0.196 4444 typ srflx raddr www.example.com rport 22222 tcptype active';
+ const arbitraryString = '<arbitrary string[0] content>;';
+
+ test(t => {
+ // The argument for RTCIceCandidateInit is optional (w3c/webrtc-pc #1153 #1166),
+ // but the constructor throws because both sdpMid and sdpMLineIndex are null by default.
+ // Note that current browsers pass this test but may throw TypeError for
+ // different reason, i.e. they don't accept empty argument.
+ // Further tests below are used to differentiate the errors.
+ assert_throws_js(TypeError, () => new RTCIceCandidate());
+ }, 'new RTCIceCandidate()');
+
+ test(t => {
+ // All fields in RTCIceCandidateInit are optional,
+ // but the constructor throws because both sdpMid and sdpMLineIndex are null by default.
+ // Note that current browsers pass this test but may throw TypeError for
+ // different reason, i.e. they don't allow undefined candidate string.
+ // Further tests below are used to differentiate the errors.
+ assert_throws_js(TypeError, () => new RTCIceCandidate({}));
+ }, 'new RTCIceCandidate({})');
+
+ test(t => {
+ // Checks that manually filling the default values for RTCIceCandidateInit
+ // still throws because both sdpMid and sdpMLineIndex are null
+ assert_throws_js(TypeError,
+ () => new RTCIceCandidate({
+ candidate: '',
+ sdpMid: null,
+ sdpMLineIndex: null,
+ usernameFragment: undefined
+ }));
+ }, 'new RTCIceCandidate({ ... }) with manually filled default values');
+
+ test(t => {
+ // Checks that explicitly setting both sdpMid and sdpMLineIndex null should throw
+ assert_throws_js(TypeError,
+ () => new RTCIceCandidate({
+ sdpMid: null,
+ sdpMLineIndex: null
+ }));
+ }, 'new RTCIceCandidate({ sdpMid: null, sdpMLineIndex: null })');
+
+ test(t => {
+ // Throws because both sdpMid and sdpMLineIndex are null by default
+ assert_throws_js(TypeError,
+ () => new RTCIceCandidate({
+ candidate: ''
+ }));
+ }, `new RTCIceCandidate({ candidate: '' })`);
+
+ test(t => {
+ // Throws because the candidate field is not nullable
+ assert_throws_js(TypeError,
+ () => new RTCIceCandidate({
+ candidate: null
+ }));
+ }, `new RTCIceCandidate({ candidate: null })`);
+
+ test(t => {
+ // Throws because both sdpMid and sdpMLineIndex are null by default
+ assert_throws_js(TypeError,
+ () => new RTCIceCandidate({
+ candidate: candidateString
+ }));
+ }, 'new RTCIceCandidate({ ... }) with valid candidate string only');
+
+ test(t => {
+ const candidate = new RTCIceCandidate({ sdpMid: 'audio' });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, `new RTCIceCandidate({ sdpMid: 'audio' })`);
+
+ test(t => {
+ const candidate = new RTCIceCandidate({ sdpMLineIndex: 0 });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, null, 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, 'new RTCIceCandidate({ sdpMLineIndex: 0 })');
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ sdpMid: 'audio',
+ sdpMLineIndex: 0
+ });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, `new RTCIceCandidate({ sdpMid: 'audio', sdpMLineIndex: 0 })`);
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ candidate: '',
+ sdpMid: 'audio'
+ });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, `new RTCIceCandidate({ candidate: '', sdpMid: 'audio' }`);
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ candidate: '',
+ sdpMLineIndex: 0
+ });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, null, 'sdpMid', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 0, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, `new RTCIceCandidate({ candidate: '', sdpMLineIndex: 0 }`);
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ candidate: candidateString,
+ sdpMid: 'audio'
+ });
+
+ assert_equals(candidate.candidate, candidateString, 'candidate');
+ assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, 'new RTCIceCandidate({ ... }) with valid candidate string and sdpMid');
+
+ test(t =>{
+ // candidate string is not validated in RTCIceCandidate
+ const candidate = new RTCIceCandidate({
+ candidate: arbitraryString,
+ sdpMid: 'audio'
+ });
+
+ assert_equals(candidate.candidate, arbitraryString, 'candidate');
+ assert_equals(candidate.sdpMid, 'audio', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, 'new RTCIceCandidate({ ... }) with invalid candidate string and sdpMid');
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ candidate: candidateString,
+ sdpMid: 'video',
+ sdpMLineIndex: 1,
+ usernameFragment: 'test'
+ });
+
+ assert_equals(candidate.candidate, candidateString, 'candidate');
+ assert_equals(candidate.sdpMid, 'video', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 1, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, 'test', 'usernameFragment');
+
+ // The following fields should match those in the candidate field
+ assert_equals(candidate.foundation, '1905690388', 'foundation');
+ assert_equals(candidate.component, 'rtp', 'component');
+ assert_equals(candidate.priority, 2113937151, 'priority');
+ assert_equals(candidate.address, '192.168.0.1', 'address');
+ assert_equals(candidate.protocol, 'udp', 'protocol');
+ assert_equals(candidate.port, 58041, 'port');
+ assert_equals(candidate.type, 'host', 'type');
+ assert_equals(candidate.tcpType, null, 'tcpType');
+ assert_equals(candidate.relatedAddress, null, 'relatedAddress');
+ assert_equals(candidate.relatedPort, null, 'relatedPort');
+ }, 'new RTCIceCandidate({ ... }) with nondefault values for all fields');
+
+ test(t => {
+ const candidate = new RTCIceCandidate({
+ candidate: candidateString2,
+ sdpMid: 'video',
+ sdpMLineIndex: 1,
+ usernameFragment: 'user1'
+ });
+
+ assert_equals(candidate.candidate, candidateString2, 'candidate');
+ assert_equals(candidate.sdpMid, 'video', 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 1, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, 'user1', 'usernameFragment');
+
+ // The following fields should match those in the candidate field
+ assert_equals(candidate.foundation, '435653019', 'foundation');
+ assert_equals(candidate.component, 'rtcp', 'component');
+ assert_equals(candidate.priority, 1845501695, 'priority');
+ assert_equals(candidate.address, '192.168.0.196', 'address');
+ assert_equals(candidate.protocol, 'tcp', 'protocol');
+ assert_equals(candidate.port, 4444, 'port');
+ assert_equals(candidate.type, 'srflx', 'type');
+ assert_equals(candidate.tcpType, 'active', 'tcpType');
+ assert_equals(candidate.relatedAddress, 'www.example.com', 'relatedAddress');
+ assert_equals(candidate.relatedPort, 22222, 'relatedPort');
+ }, 'new RTCIceCandidate({ ... }) with nondefault values for all fields, tcp candidate');
+
+ test(t => {
+ // sdpMid is not validated in RTCIceCandidate
+ const candidate = new RTCIceCandidate({
+ sdpMid: arbitraryString
+ });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, arbitraryString, 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, null, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, 'new RTCIceCandidate({ ... }) with invalid sdpMid');
+
+
+ test(t => {
+ // Some arbitrary large out of bound line index that practically
+ // do not reference any m= line in SDP.
+ // However sdpMLineIndex is not validated in RTCIceCandidate
+ // and it has no knowledge of the SDP it is associated with.
+ const candidate = new RTCIceCandidate({
+ sdpMLineIndex: 65535
+ });
+
+ assert_equals(candidate.candidate, '', 'candidate');
+ assert_equals(candidate.sdpMid, null, 'sdpMid');
+ assert_equals(candidate.sdpMLineIndex, 65535, 'sdpMLineIndex');
+ assert_equals(candidate.usernameFragment, null, 'usernameFragment');
+ }, 'new RTCIceCandidate({ ... }) with invalid sdpMLineIndex');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCIceConnectionState and RTCIceCandidatePair</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream = await getNoiseStream({audio:true});
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await listenToIceConnected(caller);
+
+ const report = await caller.getStats();
+ let succeededPairFound = false;
+ report.forEach(stats => {
+ if (stats.type == 'candidate-pair' && stats.state == 'succeeded')
+ succeededPairFound = true;
+ });
+ assert_true(succeededPairFound, 'A succeeded candidate-pair should exist');
+}, 'On ICE connected, getStats() contains a connected candidate-pair');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCIceTransport</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // createDataChannelPair
+ // awaitMessage
+
+ /*
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceRole role;
+ readonly attribute RTCIceComponent component;
+ readonly attribute RTCIceTransportState state;
+ readonly attribute RTCIceGathererState gatheringState;
+ sequence<RTCIceCandidate> getLocalCandidates();
+ sequence<RTCIceCandidate> getRemoteCandidates();
+ RTCIceCandidatePair? getSelectedCandidatePair();
+ RTCIceParameters? getLocalParameters();
+ RTCIceParameters? getRemoteParameters();
+ ...
+ };
+
+ getLocalCandidates
+ Returns a sequence describing the local ICE candidates gathered for this
+ RTCIceTransport and sent in onicecandidate
+
+ getRemoteCandidates
+ Returns a sequence describing the remote ICE candidates received by this
+ RTCIceTransport via addIceCandidate()
+
+ getSelectedCandidatePair
+ Returns the selected candidate pair on which packets are sent, or null if
+ there is no such pair.
+
+ getLocalParameters
+ Returns the local ICE parameters received by this RTCIceTransport via
+ setLocalDescription , or null if the parameters have not yet been received.
+
+ getRemoteParameters
+ Returns the remote ICE parameters received by this RTCIceTransport via
+ setRemoteDescription or null if the parameters have not yet been received.
+ */
+ function getIceTransportFromSctp(pc) {
+ const sctpTransport = pc.sctp;
+ assert_true(sctpTransport instanceof RTCSctpTransport,
+ 'Expect pc.sctp to be instantiated from RTCSctpTransport');
+
+ const dtlsTransport = sctpTransport.transport;
+ assert_true(dtlsTransport instanceof RTCDtlsTransport,
+ 'Expect sctp.transport to be an RTCDtlsTransport');
+
+ const iceTransport = dtlsTransport.iceTransport;
+ assert_true(iceTransport instanceof RTCIceTransport,
+ 'Expect dtlsTransport.transport to be an RTCIceTransport');
+
+ return iceTransport;
+ }
+
+ function validateCandidates(candidates) {
+ assert_greater_than(candidates.length, 0,
+ 'Expect at least one ICE candidate returned from get*Candidates()');
+
+ for(const candidate of candidates) {
+ assert_true(candidate instanceof RTCIceCandidate,
+ 'Expect candidate elements to be instance of RTCIceCandidate');
+ }
+ }
+
+ function validateCandidateParameter(param) {
+ assert_not_equals(param, null,
+ 'Expect candidate parameter to be non-null after data channels are connected');
+
+ assert_equals(typeof param.usernameFragment, 'string',
+ 'Expect param.usernameFragment to be set with string value');
+ assert_equals(typeof param.password, 'string',
+ 'Expect param.password to be set with string value');
+ }
+
+ function validateConnectedIceTransport(iceTransport) {
+ const { state, gatheringState, role, component } = iceTransport;
+
+ assert_true(role === 'controlling' || role === 'controlled',
+ 'Expect RTCIceRole to be either controlling or controlled, found ' + role);
+
+ assert_true(component === 'rtp' || component === 'rtcp',
+ 'Expect RTCIceComponent to be either rtp or rtcp');
+
+ assert_true(state === 'connected' || state === 'completed',
+ 'Expect ICE transport to be in connected or completed state after data channels are connected');
+
+ assert_true(gatheringState === 'gathering' || gatheringState === 'completed',
+ 'Expect ICE transport to be in gathering or completed gatheringState after data channels are connected');
+
+ validateCandidates(iceTransport.getLocalCandidates());
+ validateCandidates(iceTransport.getRemoteCandidates());
+
+ const candidatePair = iceTransport.getSelectedCandidatePair();
+ assert_not_equals(candidatePair, null,
+ 'Expect selected candidate pair to be non-null after ICE transport is connected');
+
+ assert_true(candidatePair.local instanceof RTCIceCandidate,
+ 'Expect candidatePair.local to be instance of RTCIceCandidate');
+
+ assert_true(candidatePair.remote instanceof RTCIceCandidate,
+ 'Expect candidatePair.remote to be instance of RTCIceCandidate');
+
+ validateCandidateParameter(iceTransport.getLocalParameters());
+ validateCandidateParameter(iceTransport.getRemoteParameters());
+ }
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('');
+
+ // setRemoteDescription(answer) without the other peer
+ // setting answer it's localDescription
+ return pc1.createOffer()
+ .then(offer =>
+ pc1.setLocalDescription(offer)
+ .then(() => pc2.setRemoteDescription(offer))
+ .then(() => pc2.createAnswer()))
+ .then(answer => pc1.setRemoteDescription(answer))
+ .then(() => {
+ const iceTransport = getIceTransportFromSctp(pc1);
+
+ assert_array_equals(iceTransport.getRemoteCandidates(), [],
+ 'Expect iceTransport to not have any remote candidate');
+
+ assert_equals(iceTransport.getSelectedCandidatePair(), null,
+ 'Expect selectedCandidatePair to be null');
+ });
+ }, 'Unconnected iceTransport should have empty remote candidates and selected pair');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const signalingStates = [];
+ pc.onsignalingstatechange = ev => signalingStates.push(pc.signalingState);
+ pc.addTransceiver('audio', {direction:'recvonly'});
+ const offer = await pc.createOffer();
+ const sldPromise = pc.setLocalDescription(offer);
+ const srdPromise = pc.setRemoteDescription(offer);
+ await Promise.all([sldPromise, srdPromise]);
+ assert_array_equals(signalingStates,
+ ['have-local-offer','stable','have-remote-offer']);
+}, 'setLocalDescription and setRemoteDescription are not racy');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection addTrack does not deadlock</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // This test sets up two peer connections using a sequence of operations
+ // that triggered a deadlock in Chrome. See https://crbug.com/736725.
+ // If a deadlock is introduced again, this test times out.
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const stream = await getNoiseStream(
+ {audio: false, video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const videoTrack = stream.getVideoTracks()[0];
+ pc1.addTrack(videoTrack, stream);
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const srdPromise = pc2.setRemoteDescription(offer);
+ pc2.addTrack(videoTrack, stream);
+ // The deadlock encountered in https://crbug.com/736725 occured here.
+ await srdPromise;
+ await pc2.createAnswer();
+ }, 'RTCPeerConnection addTrack does not deadlock.');
+</script>
--- /dev/null
+<!doctype html>
+<meta name="timeout" content="long">
+<title>Test RTCPeerConnection.prototype.addIceCandidate</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+// This test may be flaky, so it's in its own file.
+// The test belongs in RTCPeerConnection-addIceCandidate.
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc1.addTransceiver('video');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOffer(pc1, pc2);
+ const answer = await pc2.createAnswer();
+ // Note that sequence of the following two calls is critical
+ // for test stability.
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ await waitForState(transceiver.sender.transport, 'connected');
+}, 'Candidates are added dynamically; connection should work');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc1.addTransceiver('video');
+
+ let candidates1to2 = [];
+ let candidates2to1 = [];
+ pc1.onicecandidate = e => candidates1to2.push(e.candidate);
+ pc2.onicecandidate = e => candidates2to1.push(e.candidate);
+ const pc2GatheredCandidates = new Promise((resolve) => {
+ pc2.addEventListener('icegatheringstatechange', () => {
+ if (pc2.iceGatheringState == 'complete') {
+ resolve();
+ }
+ });
+ });
+ await exchangeOffer(pc1, pc2);
+ let answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ await pc2GatheredCandidates;
+ // Add candidates to pc1, ensuring that it goes to "connecting" state before "connected".
+ // We do not iterate/await because repeatedly awaiting while we serially add
+ // the candidates opens the opportunity to miss the 'connecting' transition.
+ const addCandidatesDone = Promise.all(candidates2to1.map(c => pc1.addIceCandidate(c)));
+ await waitForState(transceiver.sender.transport, 'connecting');
+ await addCandidatesDone;
+ await waitForState(transceiver.sender.transport, 'connected');
+}, 'Candidates are added at PC1; connection should work');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc1.addTransceiver('video');
+
+ let candidates1to2 = [];
+ let candidates2to1 = [];
+ pc1.onicecandidate = e => candidates1to2.push(e.candidate);
+ pc2.onicecandidate = e => candidates2to1.push(e.candidate);
+ const pc1GatheredCandidates = new Promise((resolve) => {
+ pc1.addEventListener('icegatheringstatechange', () => {
+ if (pc1.iceGatheringState == 'complete') {
+ resolve();
+ }
+ });
+ });
+ await exchangeOffer(pc1, pc2);
+ let answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ await pc1GatheredCandidates;
+ // Add candidates to pc2
+ // We do not iterate/await because repeatedly awaiting while we serially add
+ // the candidates opens the opportunity to miss the ICE state transitions.
+ await Promise.all(candidates1to2.map(c => pc2.addIceCandidate(c)));
+ await waitForState(transceiver.sender.transport, 'connected');
+}, 'Candidates are added at PC2; connection should work');
+
+</script>
--- /dev/null
+<!doctype html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+
+'use strict';
+
+// In this test, the promises should resolve in the execution order
+// (setLocalDescription, setLocalDescription, addIceCandidate) as is ensured by
+// the Operations Chain; if an operation is pending, executing another operation
+// will queue it. This test will fail if an Operations Chain is not implemented,
+// but it gives the implementation some slack: it only ensures that
+// addIceCandidate() is not resolved first, allowing timing issues in resolving
+// promises where the test still passes even if addIceCandidate() is resolved
+// *before* the second setLocalDescription().
+//
+// This test covers Chrome issue (https://crbug.com/1019222), but does not
+// require setLocalDescription-promises to resolve immediately which is another
+// Chrome bug (https://crbug.com/1019232). The true order is covered by the next
+// test.
+// TODO(https://crbug.com/1019232): Delete this test when the next test passes
+// in Chrome.
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+
+ const candidatePromise = new Promise(resolve => {
+ caller.onicecandidate = e => resolve(e.candidate);
+ });
+ await caller.setLocalDescription(await caller.createOffer());
+ await callee.setRemoteDescription(caller.localDescription);
+ const candidate = await candidatePromise;
+
+ // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
+ // without performing await between the calls.
+ const pendingPromises = [];
+ const resolveOrder = [];
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 1');
+ }));
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 2');
+ }));
+ pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
+ resolveOrder.push('addIceCandidate');
+ }));
+ await Promise.all(pendingPromises);
+
+ assert_equals(resolveOrder[0], 'setLocalDescription 1');
+}, 'addIceCandidate is not resolved first if 2x setLocalDescription ' +
+ 'operations are pending');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+
+ const candidatePromise = new Promise(resolve => {
+ caller.onicecandidate = e => resolve(e.candidate);
+ });
+ await caller.setLocalDescription(await caller.createOffer());
+ await callee.setRemoteDescription(caller.localDescription);
+ const candidate = await candidatePromise;
+
+ // Chain setLocalDescription(), setLocalDescription() and addIceCandidate()
+ // without performing await between the calls.
+ const pendingPromises = [];
+ const resolveOrder = [];
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 1');
+ }));
+ pendingPromises.push(callee.setLocalDescription().then(() => {
+ resolveOrder.push('setLocalDescription 2');
+ }));
+ pendingPromises.push(callee.addIceCandidate(candidate).then(() => {
+ resolveOrder.push('addIceCandidate');
+ }));
+ await Promise.all(pendingPromises);
+
+ // This test verifies that both issues described in https://crbug.com/1019222
+ // and https://crbug.com/1019232 are fixed. If this test passes in Chrome, the
+ // ICE candidate exchange issues described in
+ // https://github.com/web-platform-tests/wpt/issues/19866 should be resolved.
+ assert_array_equals(
+ resolveOrder,
+ ['setLocalDescription 1', 'setLocalDescription 2', 'addIceCandidate']);
+}, 'addIceCandidate and setLocalDescription are resolved in the correct ' +
+ 'order, as defined by the operations chain specification');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+ let events = [];
+ let pendingPromises = [];
+
+ const onCandidatePromise = new Promise(resolve => {
+ caller.onicecandidate = () => {
+ events.push('candidate generated');
+ resolve();
+ }
+ });
+ pendingPromises.push(onCandidatePromise);
+ pendingPromises.push(caller.setLocalDescription().then(() => {
+ events.push('setLocalDescription');
+ }));
+ await Promise.all(pendingPromises);
+ assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
+}, 'onicecandidate fires after resolving setLocalDescription in offerer');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ caller.addTransceiver('audio');
+ let events = [];
+ let pendingPromises = [];
+
+ caller.onicecandidate = (ev) => {
+ if (ev.candidate) {
+ callee.addIceCandidate(ev.candidate);
+ }
+ }
+ const offer = await caller.createOffer();
+ const onCandidatePromise = new Promise(resolve => {
+ callee.onicecandidate = () => {
+ events.push('candidate generated');
+ resolve();
+ }
+ });
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ pendingPromises.push(onCandidatePromise);
+ pendingPromises.push(callee.setLocalDescription(answer).then(() => {
+ events.push('setLocalDescription');
+ }));
+ await Promise.all(pendingPromises);
+ assert_array_equals(events, ['setLocalDescription', 'candidate generated']);
+}, 'onicecandidate fires after resolving setLocalDescription in answerer');
+
+</script>
--- /dev/null
+<!doctype html>
+<title>Test RTCPeerConnection.prototype.addIceCandidate</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // SDP copied from JSEP Example 7.1
+ // It contains two media streams with different ufrags
+ // to test if candidate is added to the correct stream
+ const sdp = `v=0
+o=- 4962303333179871722 1 IN IP4 0.0.0.0
+s=-
+t=0 0
+a=ice-options:trickle
+a=group:BUNDLE a1 v1
+a=group:LS a1 v1
+m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
+c=IN IP4 203.0.113.100
+a=mid:a1
+a=sendrecv
+a=rtpmap:96 opus/48000/2
+a=rtpmap:0 PCMU/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:97 telephone-event/8000
+a=rtpmap:98 telephone-event/48000
+a=maxptime:120
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
+a=ice-ufrag:ETEn
+a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10101 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+m=video 10102 UDP/TLS/RTP/SAVPF 100 101
+c=IN IP4 203.0.113.100
+a=mid:v1
+a=sendrecv
+a=rtpmap:100 VP8/90000
+a=rtpmap:101 rtx/90000
+a=fmtp:101 apt=100
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=rtcp-fb:100 ccm fir
+a=rtcp-fb:100 nack
+a=rtcp-fb:100 nack pli
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
+a=ice-ufrag:BGKk
+a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10103 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+`;
+
+ const sessionDesc = { type: 'offer', sdp };
+
+ // valid candidate attributes
+ const sdpMid1 = 'a1';
+ const sdpMLineIndex1 = 0;
+ const usernameFragment1 = 'ETEn';
+
+ const sdpMid2 = 'v1';
+ const sdpMLineIndex2 = 1;
+ const usernameFragment2 = 'BGKk';
+
+ const mediaLine1 = 'm=audio';
+ const mediaLine2 = 'm=video';
+
+ const candidateStr1 = 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
+ const candidateStr2 = 'candidate:1 2 udp 2113929470 203.0.113.100 10101 typ host';
+ const invalidCandidateStr = '(Invalid) candidate \r\n string';
+
+ const candidateLine1 = `a=${candidateStr1}`;
+ const candidateLine2 = `a=${candidateStr2}`;
+ const endOfCandidateLine = 'a=end-of-candidates';
+
+ // Copied from MDN
+ function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+ }
+
+ function is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
+ const line1 = escapeRegExp(beforeMediaLine);
+ const line2 = escapeRegExp(candidateLine);
+ const line3 = escapeRegExp(afterMediaLine);
+
+ const regex = new RegExp(`${line1}[^]+${line2}[^]+${line3}`);
+ return regex.test(sdp);
+ }
+
+ // Check that a candidate line is found after the first media line
+ // but before the second, i.e. it belongs to the first media stream
+ function assert_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine) {
+ assert_true(is_candidate_line_between(sdp, beforeMediaLine, candidateLine, afterMediaLine),
+ `Expect candidate line to be found between media lines ${beforeMediaLine} and ${afterMediaLine}`);
+ }
+
+ // Check that a candidate line is found after the second media line
+ // i.e. it belongs to the second media stream
+ function is_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
+ const line1 = escapeRegExp(beforeMediaLine);
+ const line2 = escapeRegExp(candidateLine);
+
+ const regex = new RegExp(`${line1}[^]+${line2}`);
+
+ return regex.test(sdp);
+ }
+
+ function assert_candidate_line_after(sdp, beforeMediaLine, candidateLine) {
+ assert_true(is_candidate_line_after(sdp, beforeMediaLine, candidateLine),
+ `Expect candidate line to be found after media line ${beforeMediaLine}`);
+ }
+
+ /*
+ 4.4.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.
+ */
+
+ /*
+ Success cases
+ */
+
+ // All of these should work, because all of these end up being equivalent to the
+ // same thing; an end-of-candidates signal for all levels/mids/ufrags.
+ [
+ // This is just the default. Everything else here is equivalent to this.
+ {
+ candidate: '',
+ sdpMid: null,
+ sdpMLineIndex: null,
+ usernameFragment: undefined
+ },
+ // The arg is optional, so when passing undefined we'll just get the default
+ undefined,
+ // The arg is optional, but not nullable, so we get the default again
+ null,
+ // Members in the dictionary take their default values
+ {}
+ ].forEach(init => {
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ await pc.setRemoteDescription(sessionDesc);
+ await pc.addIceCandidate(init);
+ }, `addIceCandidate(${JSON.stringify(init)}) works`);
+ });
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ await pc.setRemoteDescription(sessionDesc)
+ await pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ });
+ assert_candidate_line_after(pc.remoteDescription.sdp,
+ mediaLine1, candidateStr1);
+ }, 'Add ICE candidate after setting remote description should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate(new RTCIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ })));
+ }, 'Add ICE candidate with RTCIceCandidate should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1 }));
+ }, 'Add candidate with only valid sdpMid should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate(new RTCIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1 })));
+ }, 'Add candidate with only valid sdpMid and RTCIceCandidate should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMLineIndex: sdpMLineIndex1 }));
+ }, 'Add candidate with only valid sdpMLineIndex should succeed');
+
+ /*
+ 4.4.2. addIceCandidate
+ 4.6.2. If candidate is applied successfully, the user agent MUST queue
+ a task that runs the following steps:
+ 2. If connection.pendingRemoteDescription is non-null, and represents
+ the ICE generation for which candidate was processed, add
+ candidate to connection.pendingRemoteDescription.
+ 3. If connection.currentRemoteDescription is non-null, and represents
+ the ICE generation for which candidate was processed, add
+ candidate to connection.currentRemoteDescription.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ }))
+ .then(() => {
+ assert_candidate_line_between(pc.remoteDescription.sdp,
+ mediaLine1, candidateLine1, mediaLine2);
+ });
+ }, 'addIceCandidate with first sdpMid and sdpMLineIndex add candidate to first media stream');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr2,
+ sdpMid: sdpMid2,
+ sdpMLineIndex: sdpMLineIndex2,
+ usernameFragment: usernameFragment2
+ }))
+ .then(() => {
+ assert_candidate_line_after(pc.remoteDescription.sdp,
+ mediaLine2, candidateLine2);
+ });
+ }, 'addIceCandidate with second sdpMid and sdpMLineIndex should add candidate to second media stream');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragment: null
+ }))
+ .then(() => {
+ assert_candidate_line_between(pc.remoteDescription.sdp,
+ mediaLine1, candidateLine1, mediaLine2);
+ });
+ }, 'Add candidate for first media stream with null usernameFragment should add candidate to first media stream');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ }))
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr2,
+ sdpMid: sdpMid2,
+ sdpMLineIndex: sdpMLineIndex2,
+ usernameFragment: usernameFragment2
+ }))
+ .then(() => {
+ assert_candidate_line_between(pc.remoteDescription.sdp,
+ mediaLine1, candidateLine1, mediaLine2);
+
+ assert_candidate_line_after(pc.remoteDescription.sdp,
+ mediaLine2, candidateLine2);
+ });
+ }, 'Adding multiple candidates should add candidates to their corresponding media stream');
+
+ /*
+ 4.4.2. addIceCandidate
+ 3. If both sdpMid and sdpMLineIndex are null, return a promise rejected
+ with a newly created TypeError.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_js(t, TypeError,
+ pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: null,
+ sdpMLineIndex: null
+ })));
+ }, 'Add candidate with both sdpMid and sdpMLineIndex manually set to null should reject with TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ await pc.setRemoteDescription(sessionDesc);
+ promise_rejects_js(t, TypeError,
+ pc.addIceCandidate({candidate: candidateStr1}));
+ }, 'addIceCandidate with a candidate and neither sdpMid nor sdpMLineIndex should reject with TypeError');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_js(t, TypeError,
+ pc.addIceCandidate({
+ candidate: candidateStr1
+ })));
+ }, 'Add candidate with only valid candidate string should reject with TypeError');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_js(t, TypeError,
+ pc.addIceCandidate({
+ candidate: invalidCandidateStr,
+ sdpMid: null,
+ sdpMLineIndex: null
+ })));
+ }, 'Add candidate with invalid candidate string and both sdpMid and sdpMLineIndex null should reject with TypeError');
+
+ /*
+ 4.4.2. addIceCandidate
+ 4.3. If candidate.sdpMid is not null, run the following steps:
+ 1. If candidate.sdpMid is not equal to the mid of any media
+ description in remoteDescription , reject p with a newly
+ created OperationError and abort these steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_dom(t, 'OperationError',
+ pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: 'invalid',
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ })));
+ }, 'Add candidate with invalid sdpMid should reject with OperationError');
+
+ /*
+ 4.4.2. addIceCandidate
+ 4.4. Else, if candidate.sdpMLineIndex is not null, run the following
+ steps:
+ 1. If candidate.sdpMLineIndex is equal to or larger than the
+ number of media descriptions in remoteDescription , reject p
+ with a newly created OperationError and abort these steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_dom(t, 'OperationError',
+ pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMLineIndex: 2,
+ usernameFragement: usernameFragment1
+ })));
+ }, 'Add candidate with invalid sdpMLineIndex should reject with OperationError');
+
+ // There is an "Else" for the statement:
+ // "Else, if candidate.sdpMLineIndex is not null, ..."
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr1,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: 2,
+ usernameFragement: usernameFragment1
+ }));
+ }, 'Invalid sdpMLineIndex should be ignored if valid sdpMid is provided');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() => pc.addIceCandidate({
+ candidate: candidateStr2,
+ sdpMid: sdpMid2,
+ sdpMLineIndex: sdpMLineIndex2,
+ usernameFragment: null
+ }))
+ .then(() => {
+ assert_candidate_line_after(pc.remoteDescription.sdp,
+ mediaLine2, candidateLine2);
+ });
+ }, 'Add candidate for media stream 2 with null usernameFragment should succeed');
+
+ /*
+ 4.4.2. addIceCandidate
+ 4.6.1. If candidate could not be successfully added the user agent MUST
+ queue a task that runs the following steps:
+ 2. Reject p with a DOMException object whose name attribute has
+ the value OperationError and abort these steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(sessionDesc)
+ .then(() =>
+ promise_rejects_dom(t, 'OperationError',
+ pc.addIceCandidate({
+ candidate: invalidCandidateStr,
+ sdpMid: sdpMid1,
+ sdpMLineIndex: sdpMLineIndex1,
+ usernameFragement: usernameFragment1
+ })));
+ }, 'Add candidate with invalid candidate string should reject with OperationError');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.addTrack</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/testdriver.js"></script>
+<script src="../../resources/testdriver-vendor.js"></script>
+<script src="support/permission-helper.js"></script>
+<script src="support/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:
+ // getNoiseStream()
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+ partial interface RTCPeerConnection {
+ ...
+ sequence<RTCRtpSender> getSenders();
+ sequence<RTCRtpReceiver> getReceivers();
+ sequence<RTCRtpTransceiver> getTransceivers();
+ RTCRtpSender addTrack(MediaStreamTrack track,
+ MediaStream... streams);
+ RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ optional RTCRtpTransceiverInit init);
+ };
+
+ Note
+ While addTrack checks if the MediaStreamTrack given as an argument is
+ already being sent to avoid sending the same MediaStreamTrack twice,
+ the other ways do not, allowing the same MediaStreamTrack to be sent
+ several times simultaneously.
+ */
+
+ /*
+ 5.1. addTrack
+ 4. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ pc.close();
+ assert_throws_dom('InvalidStateError', () => pc.addTrack(track, stream))
+ }, 'addTrack when pc is closed should throw InvalidStateError');
+
+ /*
+ 5.1. addTrack
+ 8. If sender is null, run the following steps:
+ 1. Create an RTCRtpSender with track and streams and let sender be
+ the result.
+ 2. Create an RTCRtpReceiver with track.kind as kind and let receiver
+ be the result.
+ 3. Create an RTCRtpTransceiver with sender and receiver and let
+ transceiver be the result.
+ 4. Add transceiver to connection's set of transceivers.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const sender = pc.addTrack(track);
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_equals(sender.track, track,
+ `Expect sender's track to be the added track`);
+
+ const transceivers = pc.getTransceivers();
+ assert_equals(transceivers.length, 1,
+ 'Expect only one transceiver with sender added');
+
+ const [transceiver] = transceivers;
+ assert_equals(transceiver.sender, sender);
+
+ assert_array_equals([sender], pc.getSenders(),
+ 'Expect only one sender with given track added');
+
+ const { receiver } = transceiver;
+ assert_equals(receiver.track.kind, 'audio');
+ assert_array_equals([transceiver.receiver], pc.getReceivers(),
+ 'Expect only one receiver associated with transceiver added');
+ }, 'addTrack with single track argument and no stream should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const sender = pc.addTrack(track, stream);
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_equals(sender.track, track,
+ `Expect sender's track to be the added track`);
+ }, 'addTrack with single track argument and single stream should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const stream2 = new MediaStream([track]);
+ const sender = pc.addTrack(track, stream, stream2);
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_equals(sender.track, track,
+ `Expect sender's track to be the added track`);
+ }, 'addTrack with single track argument and multiple streams should succeed');
+
+ /*
+ 5.1. addTrack
+ 5. Let senders be the result of executing the CollectSenders algorithm.
+ If an RTCRtpSender for track already exists in senders, throw an
+ InvalidAccessError.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ pc.addTrack(track, stream);
+ assert_throws_dom('InvalidAccessError', () => pc.addTrack(track, stream));
+ }, 'Adding the same track multiple times should throw InvalidAccessError');
+
+ /*
+ 5.1. addTrack
+ 6. The steps below describe how to determine if an existing sender can
+ be reused.
+
+ If any RTCRtpSender object in senders matches all the following
+ criteria, let sender be that object, or null otherwise:
+ - The sender's track is null.
+ - The transceiver kind of the RTCRtpTransceiver, associated with
+ the sender, matches track's kind.
+ - The sender has never been used to send. More precisely, the
+ RTCRtpTransceiver associated with the sender has never had a
+ currentDirection of sendrecv or sendonly.
+ 7. If sender is not null, run the following steps to use that sender:
+ 1. Set sender.track to track.
+ 3. Enable sending direction on the RTCRtpTransceiver associated
+ with sender.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio', { direction: 'recvonly' });
+ assert_equals(transceiver.sender.track, null);
+ assert_equals(transceiver.direction, 'recvonly');
+
+ await setMediaPermission("granted", ["microphone"]);
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track);
+
+ assert_equals(sender, transceiver.sender);
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_array_equals([sender], pc.getSenders());
+ }, 'addTrack with existing sender with null track, same kind, and recvonly direction should reuse sender');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.sender.track, null);
+ assert_equals(transceiver.direction, 'sendrecv');
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track);
+
+ assert_equals(sender.track, track);
+ assert_equals(sender, transceiver.sender);
+ }, 'addTrack with existing sender that has not been used to send should reuse the sender');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = caller.addTransceiver(track);
+ {
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ }
+ assert_equals(transceiver.currentDirection, 'sendonly');
+
+ caller.removeTrack(transceiver.sender);
+ {
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ }
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, 'inactive');
+
+ // |transceiver.sender| is currently not used for sending, but it should not
+ // be reused because it has been used for sending before.
+ const sender = caller.addTrack(track);
+ assert_true(sender != null);
+ assert_not_equals(sender, transceiver.sender);
+ }, 'addTrack with existing sender that has been used to send should create new sender');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('video', { direction: 'recvonly' });
+ assert_equals(transceiver.sender.track, null);
+ assert_equals(transceiver.direction, 'recvonly');
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track);
+
+ assert_equals(sender.track, track);
+ assert_not_equals(sender, transceiver.sender);
+
+ const senders = pc.getSenders();
+ assert_equals(senders.length, 2,
+ 'Expect 2 senders added to connection');
+
+ assert_true(senders.includes(sender),
+ 'Expect senders list to include sender');
+
+ assert_true(senders.includes(transceiver.sender),
+ `Expect senders list to include first transceiver's sender`);
+ }, 'addTrack with existing sender with null track, different kind, and recvonly direction should create new sender');
+
+ /*
+ TODO
+ 5.1. addTrack
+ 3. Let streams be a list of MediaStream objects constructed from the
+ method's remaining arguments, or an empty list if the method was
+ called with a single argument.
+ 6. The steps below describe how to determine if an existing sender can
+ be reused. Doing so will cause future calls to createOffer and
+ createAnswer to mark the corresponding media description as sendrecv
+ or sendonly and add the MSID of the track added, as defined in [JSEP]
+ (section 5.2.2. and section 5.3.2.).
+
+ Non-Testable
+ 5.1. addTrack
+ 7. If sender is not null, run the following steps to use that sender:
+ 2. Set sender's [[associated MediaStreams]] to streams.
+
+ Tested in RTCPeerConnection-onnegotiationneeded.html:
+ 5.1. addTrack
+ 10. Update the negotiation-needed flag for connection.
+
+ */
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = caller.addTransceiver(track);
+ // Note that this test doesn't process canididates.
+ {
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ }
+ assert_equals(transceiver.currentDirection, 'sendonly');
+ await waitForIceGatheringState(caller, ['complete']);
+ await waitForIceGatheringState(callee, ['complete']);
+
+ const second_stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => second_stream.getTracks().forEach(track => track.stop()));
+ // There may be callee candidates in flight. It seems that waiting
+ // for a createOffer() is enough time to let them complete processing.
+ // TODO(https://crbug.com/webrtc/13095): Fix bug and remove.
+ await caller.createOffer();
+
+ const [second_track] = second_stream.getTracks();
+ caller.onicecandidate = t.unreached_func(
+ 'No caller candidates should be generated.');
+ callee.onicecandidate = t.unreached_func(
+ 'No callee candidates should be generated.');
+ caller.addTrack(second_track);
+ {
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ }
+ // Check that we're bundled.
+ const [first_transceiver, second_transceiver] = caller.getTransceivers();
+ assert_equals(first_transceiver.transport, second_transceiver.transport);
+
+ }, 'Adding more tracks does not generate more candidates if bundled');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ pc1.addTrack(track);
+ const offer = await pc1.createOffer();
+ // We do not await here; we want to ensure that the transceiver this creates
+ // is untouched by addTrack, and that addTrack creates _another_ transceiver
+ const srdPromise = pc2.setRemoteDescription(offer);
+
+ const sender = pc2.addTrack(track);
+
+ await srdPromise;
+
+ assert_equals(pc2.getTransceivers().length, 1, "Should have 1 transceiver");
+ assert_equals(pc2.getTransceivers()[0].sender, sender, "The transceiver should be the one added by addTrack");
+ }, 'Calling addTrack while sRD(offer) is pending should allow the new remote transceiver to be the same one that addTrack creates');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('video');
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const offer = await pc1.createOffer();
+ const srdPromise = pc2.setRemoteDescription(offer);
+ assert_equals(pc2.getTransceivers().length, 0);
+ pc2.addTrack(track);
+ assert_equals(pc2.getTransceivers().length, 1);
+ const transceiver0 = pc2.getTransceivers()[0];
+ assert_equals(transceiver0.mid, null);
+ await srdPromise;
+ assert_equals(pc2.getTransceivers().length, 2);
+ const transceiver1 = pc2.getTransceivers()[1];
+ assert_equals(transceiver0.mid, null);
+ assert_not_equals(transceiver1.mid, null);
+ }, 'When addTrack is called while sRD is in progress, and both addTrack and sRD add a transceiver of different media types, the addTrack transceiver should come first, and then the sRD transceiver.');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.addTransceiver</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://rawgit.com/w3c/webrtc-pc/cc8d80f455b86c8041d63bceb8b457f45c72aa89/webrtc.html
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+
+ partial interface RTCPeerConnection {
+ sequence<RTCRtpSender> getSenders();
+ sequence<RTCRtpReceiver> getReceivers();
+ sequence<RTCRtpTransceiver> getTransceivers();
+ RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ optional RTCRtpTransceiverInit init);
+ ...
+ };
+
+ dictionary RTCRtpTransceiverInit {
+ RTCRtpTransceiverDirection direction = "sendrecv";
+ sequence<MediaStream> streams;
+ sequence<RTCRtpEncodingParameters> sendEncodings;
+ };
+
+ enum RTCRtpTransceiverDirection {
+ "sendrecv",
+ "sendonly",
+ "recvonly",
+ "inactive"
+ };
+
+ 5.2. RTCRtpSender Interface
+
+ interface RTCRtpSender {
+ readonly attribute MediaStreamTrack? track;
+ ...
+ };
+
+ 5.3. RTCRtpReceiver Interface
+
+ interface RTCRtpReceiver {
+ readonly attribute MediaStreamTrack track;
+ ...
+ };
+
+ 5.4. RTCRtpTransceiver Interface
+
+ interface RTCRtpTransceiver {
+ readonly attribute DOMString? mid;
+ [SameObject]
+ readonly attribute RTCRtpSender sender;
+ [SameObject]
+ readonly attribute RTCRtpReceiver receiver;
+ readonly attribute boolean stopped;
+ readonly attribute RTCRtpTransceiverDirection direction;
+ readonly attribute RTCRtpTransceiverDirection? currentDirection;
+ ...
+ };
+
+ Note
+ While addTrack checks if the MediaStreamTrack given as an argument is
+ already being sent to avoid sending the same MediaStreamTrack twice,
+ the other ways do not, allowing the same MediaStreamTrack to be sent
+ several times simultaneously.
+ */
+
+ /*
+ 5.1. addTransceiver
+ 3. If the first argument is a string, let it be kind and run the following steps:
+ 1. If kind is not a legal MediaStreamTrack kind, throw a TypeError.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_idl_attribute(pc, 'addTransceiver');
+ assert_throws_js(TypeError, () => pc.addTransceiver('invalid'));
+ }, 'addTransceiver() with string argument as invalid kind should throw TypeError');
+
+ /*
+ 5.1. addTransceiver
+ The initial value of mid is null.
+
+ 3. If the dictionary argument is present, let direction be the value of the
+ direction member. Otherwise let direction be sendrecv.
+ 4. If the first argument is a string, let it be kind and run the following steps:
+ 2. Let track be null.
+ 8. Create an RTCRtpSender with track, streams and sendEncodings and let
+ sender be the result.
+ 9. Create an RTCRtpReceiver with kind and let receiver be the result.
+ 10. Create an RTCRtpTransceiver with sender, receiver and direction, and let
+ transceiver be the result.
+ 11. Add transceiver to connection's set of transceivers.
+
+ 5.2. RTCRtpSender Interface
+ Create an RTCRtpSender
+ 2. Set sender.track to track.
+
+ 5.3. RTCRtpReceiver Interface
+ Create an RTCRtpReceiver
+ 2. Let track be a new MediaStreamTrack object [GETUSERMEDIA]. The source of
+ track is a remote source provided by receiver.
+ 3. Initialize track.kind to kind.
+ 5. Initialize track.label to the result of concatenating the string "remote "
+ with kind.
+ 6. Initialize track.readyState to live.
+ 7. Initialize track.muted to true.
+ 8. Set receiver.track to track.
+
+ 5.4. RTCRtpTransceiver Interface
+ Create an RTCRtpTransceiver
+ 2. Set transceiver.sender to sender.
+ 3. Set transceiver.receiver to receiver.
+ 4. Let transceiver have a [[Direction]] internal slot, initialized to direction.
+ 5. Let transceiver have a [[CurrentDirection]] internal slot, initialized
+ to null.
+ 6. Set transceiver.stopped to false.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_idl_attribute(pc, 'addTransceiver');
+
+ const transceiver = pc.addTransceiver('audio');
+ assert_true(transceiver instanceof RTCRtpTransceiver,
+ 'Expect transceiver to be instance of RTCRtpTransceiver');
+
+ assert_equals(transceiver.mid, null);
+ assert_equals(transceiver.stopped, false);
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_equals(transceiver.currentDirection, null);
+
+ assert_array_equals([transceiver], pc.getTransceivers(),
+ `Expect added transceiver to be the only element in connection's list of transceivers`);
+
+ const sender = transceiver.sender;
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_equals(sender.track, null);
+
+ assert_array_equals([sender], pc.getSenders(),
+ `Expect added sender to be the only element in connection's list of senders`);
+
+ const receiver = transceiver.receiver;
+ assert_true(receiver instanceof RTCRtpReceiver,
+ 'Expect receiver to be instance of RTCRtpReceiver');
+
+ const track = receiver.track;
+ assert_true(track instanceof MediaStreamTrack,
+ 'Expect receiver.track to be instance of MediaStreamTrack');
+
+ assert_equals(track.kind, 'audio');
+ assert_equals(track.readyState, 'live');
+ assert_equals(track.muted, true);
+
+ assert_array_equals([receiver], pc.getReceivers(),
+ `Expect added receiver to be the only element in connection's list of receivers`);
+
+ }, `addTransceiver('audio') should return an audio transceiver`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_idl_attribute(pc, 'addTransceiver');
+
+ const transceiver = pc.addTransceiver('video');
+ assert_true(transceiver instanceof RTCRtpTransceiver,
+ 'Expect transceiver to be instance of RTCRtpTransceiver');
+
+ assert_equals(transceiver.mid, null);
+ assert_equals(transceiver.stopped, false);
+ assert_equals(transceiver.direction, 'sendrecv');
+
+ assert_array_equals([transceiver], pc.getTransceivers(),
+ `Expect added transceiver to be the only element in connection's list of transceivers`);
+
+ const sender = transceiver.sender;
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_equals(sender.track, null);
+
+ assert_array_equals([sender], pc.getSenders(),
+ `Expect added sender to be the only element in connection's list of senders`);
+
+ const receiver = transceiver.receiver;
+ assert_true(receiver instanceof RTCRtpReceiver,
+ 'Expect receiver to be instance of RTCRtpReceiver');
+
+ const track = receiver.track;
+ assert_true(track instanceof MediaStreamTrack,
+ 'Expect receiver.track to be instance of MediaStreamTrack');
+
+ assert_equals(track.kind, 'video');
+ assert_equals(track.readyState, 'live');
+ assert_equals(track.muted, true);
+
+ assert_array_equals([receiver], pc.getReceivers(),
+ `Expect added receiver to be the only element in connection's list of receivers`);
+
+ }, `addTransceiver('video') should return a video transceiver`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' });
+ assert_equals(transceiver.direction, 'sendonly');
+ }, `addTransceiver() with direction sendonly should have result transceiver.direction be the same`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio', { direction: 'inactive' });
+ assert_equals(transceiver.direction, 'inactive');
+ }, `addTransceiver() with direction inactive should have result transceiver.direction be the same`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_idl_attribute(pc, 'addTransceiver');
+ assert_throws_js(TypeError, () =>
+ pc.addTransceiver('audio', { direction: 'invalid' }));
+ }, `addTransceiver() with invalid direction should throw TypeError`);
+
+ /*
+ 5.1. addTransceiver
+ 5. If the first argument is a MediaStreamTrack , let it be track and let
+ kind be track.kind.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track);
+ const { sender, receiver } = transceiver;
+
+ assert_true(sender instanceof RTCRtpSender,
+ 'Expect sender to be instance of RTCRtpSender');
+
+ assert_true(receiver instanceof RTCRtpReceiver,
+ 'Expect receiver to be instance of RTCRtpReceiver');
+
+ assert_equals(sender.track, track,
+ 'Expect sender.track should be the track that is added');
+
+ const receiverTrack = receiver.track;
+ assert_true(receiverTrack instanceof MediaStreamTrack,
+ 'Expect receiver.track to be instance of MediaStreamTrack');
+
+ assert_equals(receiverTrack.kind, 'audio',
+ `receiver.track should have the same kind as added track's kind`);
+
+ assert_equals(receiverTrack.readyState, 'live');
+ assert_equals(receiverTrack.muted, true);
+
+ assert_array_equals([transceiver], pc.getTransceivers(),
+ `Expect added transceiver to be the only element in connection's list of transceivers`);
+
+ assert_array_equals([sender], pc.getSenders(),
+ `Expect added sender to be the only element in connection's list of senders`);
+
+ assert_array_equals([receiver], pc.getReceivers(),
+ `Expect added receiver to be the only element in connection's list of receivers`);
+
+ }, 'addTransceiver(track) should have result with sender.track be given track');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver1 = pc.addTransceiver(track);
+ const transceiver2 = pc.addTransceiver(track);
+
+ assert_not_equals(transceiver1, transceiver2);
+
+ const sender1 = transceiver1.sender;
+ const sender2 = transceiver2.sender;
+
+ assert_not_equals(sender1, sender2);
+ assert_equals(transceiver1.sender.track, track);
+ assert_equals(transceiver2.sender.track, track);
+
+ const transceivers = pc.getTransceivers();
+ assert_equals(transceivers.length, 2);
+ assert_true(transceivers.includes(transceiver1));
+ assert_true(transceivers.includes(transceiver2));
+
+ const senders = pc.getSenders();
+ assert_equals(senders.length, 2);
+ assert_true(senders.includes(sender1));
+ assert_true(senders.includes(sender2));
+
+ }, 'addTransceiver(track) multiple times should create multiple transceivers');
+
+ /*
+ 5.1. addTransceiver
+ 6. Verify that each rid value in sendEncodings is composed only of
+ case-sensitive alphanumeric characters (a-z, A-Z, 0-9) up to a maximum
+ of 16 characters. If one of the RIDs does not meet these requirements,
+ throw a TypeError.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ assert_idl_attribute(pc, 'addTransceiver');
+
+ assert_throws_js(TypeError, () =>
+ pc.addTransceiver('audio', {
+ sendEncodings: [{
+ rid: '@Invalid!'
+ }]
+ }));
+ }, 'addTransceiver() with rid containing invalid non-alphanumeric characters should throw TypeError');
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ assert_idl_attribute(pc, 'addTransceiver');
+
+ assert_throws_js(TypeError, () =>
+ pc.addTransceiver('audio', {
+ sendEncodings: [{
+ rid: 'a'.repeat(17)
+ }]
+ }));
+ }, 'addTransceiver() with rid longer than 16 characters should throw TypeError');
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('audio', {
+ sendEncodings: [{
+ rid: 'foo'
+ }]
+ });
+ }, `addTransceiver() with valid rid value should succeed`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio', {
+ sendEncodings: [{
+ dtx: 'enabled',
+ active: false,
+ ptime: 5,
+ maxBitrate: 8,
+ maxFramerate: 25,
+ rid: 'foo'
+ }]
+ });
+ }, `addTransceiver() with valid sendEncodings should succeed`);
+
+ /*
+ TODO
+ 5.1. addTransceiver
+ - Adding a transceiver will cause future calls to createOffer to add a media
+ description for the corresponding transceiver, as defined in [JSEP]
+ (section 5.2.2.).
+
+ - Setting a new RTCSessionDescription may change mid to a non-null value,
+ as defined in [JSEP] (section 5.5. and section 5.6.).
+
+ 1. If the dictionary argument is present, and it has a streams member, let
+ streams be that list of MediaStream objects.
+
+ 5.2. RTCRtpSender Interface
+ Create an RTCRtpSender
+ 3. Let sender have an [[associated MediaStreams]] internal slot, representing
+ a list of MediaStream objects that the MediaStreamTrack object of this
+ sender is associated with.
+
+ 4. Set sender's [[associated MediaStreams]] slot to streams.
+
+ 5. Let sender have a [[send encodings]] internal slot, representing a list
+ of RTCRtpEncodingParameters dictionaries.
+
+ 6. If sendEncodings is given as input to this algorithm, and is non-empty,
+ set the [[send encodings]] slot to sendEncodings. Otherwise, set it to a
+ list containing a single RTCRtpEncodingParameters with active set to true.
+
+ 5.3. RTCRtpReceiver Interface
+ Create an RTCRtpReceiver
+ 4. If an id string, id, was given as input to this algorithm, initialize
+ track.id to id. (Otherwise the value generated when track was created
+ will be used.)
+
+ Tested in RTCPeerConnection-onnegotiationneeded.html
+ 5.1. addTransceiver
+ 12. Update the negotiation-needed flag for connection.
+
+ Out of Scope
+ 5.1. addTransceiver
+ 8. If sendEncodings is set, then subsequent calls to createOffer will be
+ configured to send multiple RTP encodings as defined in [JSEP]
+ (section 5.2.2. and section 5.2.1.).
+
+ When setRemoteDescription is called with a corresponding remote
+ description that is able to receive multiple RTP encodings as defined
+ in [JSEP] (section 3.7.), the RTCRtpSender may send multiple RTP
+ encodings and the parameters retrieved via the transceiver's
+ sender.getParameters() will reflect the encodings negotiated.
+
+ 9. This specification does not define how to configure createOffer to
+ receive multiple RTP encodings. However when setRemoteDescription is
+ called with a corresponding remote description that is able to send
+ multiple RTP encodings as defined in [JSEP], the RTCRtpReceiver may
+ receive multiple RTP encodings and the parameters retrieved via the
+ transceiver's receiver.getParameters() will reflect the encodings
+ negotiated.
+
+ Coverage Report
+ Tested Not-Tested Non-Testable Total
+ addTransceiver 14 1 3 18
+ Create Sender 3 4 0 7
+ Create Receiver 8 1 0 9
+ Create Transceiver 7 0 0 7
+
+ Total 32 6 3 41
+ */
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection canTrickleIceCandidates tests</title>
+</head>
+<body>
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script type="text/javascript">
+ // tests support for RTCPeerConnection.canTrickleIceCandidates:
+ // http://w3c.github.io/webrtc-pc/#dom-rtcpeerconnection-cantrickleicecandidates
+ const sdp = 'v=0\r\n' +
+ 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n' +
+ 'a=ice-options:trickle\r\n' +
+ 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
+ 'c=IN IP4 0.0.0.0\r\n' +
+ 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
+ 'a=ice-ufrag:someufrag\r\n' +
+ 'a=ice-pwd:somelongpwdwithenoughrandomness\r\n' +
+ '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\r\n' +
+ 'a=setup:actpass\r\n' +
+ 'a=rtcp-mux\r\n' +
+ 'a=mid:mid1\r\n' +
+ 'a=sendonly\r\n' +
+ 'a=msid:stream1 track1\r\n' +
+ 'a=ssrc:1001 cname:some\r\n' +
+ 'a=rtpmap:111 opus/48000/2\r\n';
+
+ test(function() {
+ var pc = new RTCPeerConnection();
+ assert_equals(pc.canTrickleIceCandidates, null, 'canTrickleIceCandidates property is null');
+ }, 'canTrickleIceCandidates property is null prior to setRemoteDescription');
+
+ promise_test(function(t) {
+ var pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp}))
+ .then(function() {
+ assert_true(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is true after setRemoteDescription');
+ })
+ }, 'canTrickleIceCandidates property is true after setRemoteDescription with a=ice-options:trickle');
+
+ promise_test(function(t) {
+ var pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.replace('a=ice-options:trickle\r\n', '')}))
+ .then(function() {
+ assert_false(pc.canTrickleIceCandidates, 'canTrickleIceCandidates property is false after setRemoteDescription');
+ })
+ }, 'canTrickleIceCandidates property is false after setRemoteDescription without a=ice-options:trickle');
+</script>
+
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ let resolveIceCandidatePromise = null;
+ const iceCandidatePromise = new Promise(r => resolveIceCandidatePromise = r);
+ pc.onicecandidate = e => {
+ resolveIceCandidatePromise(pc.localDescription.sdp);
+ pc.onicecandidate = null;
+ }
+ pc.addTransceiver("audio");
+ await pc.setLocalDescription(await pc.createOffer());
+ assert_false(pc.localDescription.sdp.includes("a=candidate:"),
+ "localDescription is missing candidate before onicecandidate");
+ // The localDescription at the time of the onicecandidate event.
+ const localDescriptionSdp = await iceCandidatePromise;
+ assert_true(localDescriptionSdp.includes("a=candidate:"),
+ "localDescription contains candidate after onicecandidate");
+}, 'localDescription contains candidates');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.connectionState</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.htm
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // exchangeIceCandidates
+ // exchangeOfferAnswer
+
+ /*
+ 4.3.2. Interface Definition
+ interface RTCPeerConnection : EventTarget {
+ ...
+ readonly attribute RTCPeerConnectionState connectionState;
+ attribute EventHandler onconnectionstatechange;
+ };
+
+ 4.4.3. RTCPeerConnectionState Enum
+ enum RTCPeerConnectionState {
+ "new",
+ "connecting",
+ "connected",
+ "disconnected",
+ "failed",
+ "closed"
+ };
+
+ 5.5. RTCDtlsTransport Interface
+ interface RTCDtlsTransport {
+ readonly attribute RTCIceTransport iceTransport;
+ readonly attribute RTCDtlsTransportState state;
+ ...
+ };
+
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceTransportState state;
+ ...
+ };
+
+ enum RTCIceTransportState {
+ "new",
+ "checking",
+ "connected",
+ "completed",
+ "failed",
+ "disconnected",
+ "closed"
+ };
+ */
+
+ /*
+ 4.4.3. RTCPeerConnectionState Enum
+ new
+ Any of the RTCIceTransports or RTCDtlsTransports are in the new
+ state and none of the transports are in the connecting, checking,
+ failed or disconnected state, or all transports are in the closed state.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.connectionState, 'new');
+ }, 'Initial connectionState should be new');
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ pc.close();
+ assert_equals(pc.connectionState, 'closed');
+ }, 'Closing the connection should set connectionState to closed');
+
+ /*
+ 4.4.3. RTCPeerConnectionState Enum
+ connected
+ All RTCIceTransports and RTCDtlsTransports are in the connected,
+ completed or closed state and at least of them is in the connected
+ or completed state.
+
+ 5.5. RTCDtlsTransportState
+ connected
+ DTLS has completed negotiation of a secure connection.
+
+ 5.6. RTCIceTransportState
+ connected
+ The RTCIceTransport has found a usable connection, but is still
+ checking other candidate pairs to see if there is a better connection.
+ It may also still be gathering and/or waiting for additional remote
+ candidates. If consent checks [RFC7675] fail on the connection in use,
+ and there are no other successful candidate pairs available, then the
+ state transitions to "checking" (if there are candidate pairs remaining
+ to be checked) or "disconnected" (if there are no candidate pairs to
+ check, but the peer is still gathering and/or waiting for additional
+ remote candidates).
+
+ completed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate
+ pairs and found a connection. If consent checks [RFC7675] subsequently
+ fail on all successful candidate pairs, the state transitions to "failed".
+ */
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ let had_connecting = false;
+
+ const onConnectionStateChange = t.step_func(() => {
+ const {connectionState} = pc1;
+ if (connectionState === 'connecting') {
+ had_connecting = true;
+ } else if (connectionState === 'connected') {
+ assert_true(had_connecting, "state should pass connecting before reaching connected");
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ pc1.addEventListener('connectionstatechange', onConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have connected connection state');
+
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const onConnectionStateChange = t.step_func(() => {
+ const {connectionState} = pc1;
+ if (connectionState === 'connected') {
+ const sctpTransport = pc1.sctp;
+
+ const dtlsTransport = sctpTransport.transport;
+ assert_equals(dtlsTransport.state, 'connected',
+ 'Expect DTLS transport to be in connected state');
+
+ const iceTransport = dtlsTransport.iceTransport
+ assert_true(iceTransport.state === 'connected' ||
+ iceTransport.state === 'completed',
+ 'Expect ICE transport to be in connected or completed state');
+
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ pc1.addEventListener('connectionstatechange', onConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have transports in connected state');
+
+ /*
+ TODO
+ 4.4.3. RTCPeerConnectionState Enum
+ connecting
+ Any of the RTCIceTransports or RTCDtlsTransports are in the
+ connecting or checking state and none of them is in the failed state.
+
+ disconnected
+ Any of the RTCIceTransports or RTCDtlsTransports are in the disconnected
+ state and none of them are in the failed or connecting or checking state.
+
+ failed
+ Any of the RTCIceTransports or RTCDtlsTransports are in a failed state.
+
+ closed
+ The RTCPeerConnection object's [[isClosed]] slot is true.
+
+ 5.5. RTCDtlsTransportState
+ new
+ DTLS has not started negotiating yet.
+
+ connecting
+ DTLS is in the process of negotiating a secure connection.
+
+ closed
+ The transport has been closed.
+
+ failed
+ The transport has failed as the result of an error (such as a failure
+ to validate the remote fingerprint).
+
+ 5.6. RTCIceTransportState
+ new
+ The RTCIceTransport is gathering candidates and/or waiting for
+ remote candidates to be supplied, and has not yet started checking.
+
+ checking
+ The RTCIceTransport has received at least one remote candidate and
+ is checking candidate pairs and has either not yet found a connection
+ or consent checks [RFC7675] have failed on all previously successful
+ candidate pairs. In addition to checking, it may also still be gathering.
+
+ failed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate pairs,
+ and all pairs have either failed connectivity checks or have lost consent.
+
+ disconnected
+ The ICE Agent has determined that connectivity is currently lost for this
+ RTCIceTransport . This is more aggressive than failed, and may trigger
+ intermittently (and resolve itself without action) on a flaky network.
+ The way this state is determined is implementation dependent.
+
+ Examples include:
+ Losing the network interface for the connection in use.
+ Repeatedly failing to receive a response to STUN requests.
+
+ Alternatively, the RTCIceTransport has finished checking all existing
+ candidates pairs and failed to find a connection (or consent checks
+ [RFC7675] once successful, have now failed), but it is still gathering
+ and/or waiting for additional remote candidates.
+
+ closed
+ The RTCIceTransport has shut down and is no longer responding to STUN requests.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+
+ await exchangeOfferAnswer(caller, callee);
+
+ assert_equals(caller.iceConnectionState, 'new');
+ assert_equals(callee.iceConnectionState, 'new');
+ }, 'connectionState remains new when not adding remote ice candidates');
+
+ promise_test(async t => {
+
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+
+ const states = [];
+ caller.addEventListener('connectionstatechange', () => states.push(caller.connectionState));
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+
+ await listenToConnected(caller);
+
+ assert_array_equals(states, ['connecting', 'connected']);
+ }, 'connectionState transitions to connected via connecting');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc2);
+
+ pc2.onconnectionstatechange = t.unreached_func();
+ pc2.close();
+ assert_equals(pc2.connectionState, 'closed');
+ await new Promise(r => t.step_timeout(r, 100));
+ }, 'Closing a PeerConnection should not fire connectionstatechange event');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection constructor</title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+test(function() {
+ assert_equals(RTCPeerConnection.length, 0);
+}, 'RTCPeerConnection.length');
+
+// These are used for string and number dictionary members to see if they are
+// being accessed at all.
+const toStringThrows = { toString: function() { throw new Error; } };
+const toNumberThrows = Symbol();
+
+// Test the first argument of the constructor. The key is the argument itself,
+// and the value is the first argument for assert_throws_js, or false if no
+// exception should be thrown.
+const testArgs = {
+ // No argument or equivalent.
+ '': false,
+ 'null': false,
+ 'undefined': false,
+ '{}': false,
+
+ // certificates
+ '{ certificates: null }': TypeError,
+ '{ certificates: undefined }': false,
+ '{ certificates: [] }': false,
+ '{ certificates: [null] }': TypeError,
+ '{ certificates: [undefined] }': TypeError,
+
+ // iceCandidatePoolSize
+ '{ iceCandidatePoolSize: toNumberThrows }': TypeError,
+}
+
+for (const arg in testArgs) {
+ const expr = 'new RTCPeerConnection(' + arg + ')';
+ test(function() {
+ const throws = testArgs[arg];
+ if (throws) {
+ assert_throws_js(throws, function() {
+ eval(expr);
+ });
+ } else {
+ eval(expr);
+ }
+ }, expr);
+}
+
+// The initial values of attributes of RTCPeerConnection.
+const initialState = {
+ 'localDescription': null,
+ 'currentLocalDescription': null,
+ 'pendingLocalDescription': null,
+ 'remoteDescription': null,
+ 'currentRemoteDescription': null,
+ 'pendingRemoteDescription': null,
+ 'signalingState': 'stable',
+ 'iceGatheringState': 'new',
+ 'iceConnectionState': 'new',
+ 'connectionState': 'new',
+ 'canTrickleIceCandidates': null,
+ // TODO: defaultIceServers
+};
+
+for (const attr in initialState) {
+ test(function() {
+ // Use one RTCPeerConnection instance for all initial value tests.
+ if (!window.pc) {
+ window.pc = new RTCPeerConnection;
+ }
+ assert_equals(window.pc[attr], initialState[attr]);
+ }, attr + ' initial value');
+}
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.createAnswer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ await promise_rejects_dom(t, 'InvalidStateError', pc.createAnswer());
+}, 'createAnswer() with null remoteDescription should reject with InvalidStateError');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ // generateDataChannelOffer() is defined in RTCPeerConnection-helper.js.
+ const offer = await generateDataChannelOffer(pc);
+ await pc.setRemoteDescription(offer);
+ pc.close();
+ await promise_rejects_dom(t, 'InvalidStateError', pc.createAnswer());
+}, 'createAnswer() when connection is closed should reject with InvalidStateError');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.createDataChannel</title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+const stopTracks = (...streams) => {
+ streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
+};
+
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+/*
+ 6.1. RTCPeerConnection Interface Extensions
+
+ partial interface RTCPeerConnection {
+ [...]
+ RTCDataChannel createDataChannel(USVString label,
+ optional RTCDataChannelInit dataChannelDict);
+ [...]
+ };
+
+ 6.2. RTCDataChannel
+
+ interface RTCDataChannel : EventTarget {
+ readonly attribute USVString label;
+ readonly attribute boolean ordered;
+ readonly attribute unsigned short? maxPacketLifeTime;
+ readonly attribute unsigned short? maxRetransmits;
+ readonly attribute USVString protocol;
+ readonly attribute boolean negotiated;
+ readonly attribute unsigned short? id;
+ readonly attribute RTCDataChannelState readyState;
+ readonly attribute unsigned long bufferedAmount;
+ attribute unsigned long bufferedAmountLowThreshold;
+ [...]
+ attribute DOMString binaryType;
+ [...]
+ };
+
+ dictionary RTCDataChannelInit {
+ boolean ordered = true;
+ unsigned short maxPacketLifeTime;
+ unsigned short maxRetransmits;
+ USVString protocol = "";
+ boolean negotiated = false;
+ [EnforceRange]
+ unsigned short id;
+ };
+ */
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.createDataChannel.length, 1);
+ assert_throws_js(TypeError, () => pc.createDataChannel());
+}, 'createDataChannel with no argument should throw TypeError');
+
+/*
+ 6.2. createDataChannel
+ 2. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ pc.close();
+ assert_equals(pc.signalingState, 'closed', 'signaling state');
+ assert_throws_dom('InvalidStateError', () => pc.createDataChannel(''));
+}, 'createDataChannel with closed connection should throw InvalidStateError');
+
+/*
+ 6.1. createDataChannel
+ 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
+ first argument.
+ 6. Let options be the second argument.
+ 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
+ option's maxPacketLifeTime member, if present, otherwise null.
+ 8. Let channel have a [[ReadyState]] internal slot initialized to "connecting".
+ 9. Let channel have a [[BufferedAmount]] internal slot initialized to 0.
+ 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
+ option's maxRetransmits member, if present, otherwise null.
+ 11. Let channel have an [[Ordered]] internal slot initialized to option's
+ ordered member.
+ 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
+ protocol member.
+ 14. Let channel have a [[Negotiated]] internal slot initialized to option's negotiated
+ member.
+ 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id
+ member, if it is present and [[Negotiated]] is true, otherwise null.
+ 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
+ createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
+ transport has already been negotiated, then initialize [[DataChannelId]] to a value
+ generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
+ to the next step. If no available ID could be generated, or if the value of the
+ [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
+ OperationError exception.
+
+ Note
+ If the [[DataChannelId]] slot is null after this step, it will be populated once
+ the DTLS role is determined during the process of setting an RTCSessionDescription.
+ 22. If channel is the first RTCDataChannel created on connection, update the
+ negotiation-needed flag for connection.
+
+
+ 6.2. RTCDataChannel
+
+ A RTCDataChannel, created with createDataChannel or dispatched via a
+ RTCDataChannelEvent, MUST initially be in the connecting state
+
+ bufferedAmountLowThreshold
+ [...] The bufferedAmountLowThreshold is initially zero on each new RTCDataChannel,
+ but the application may change its value at any time.
+
+ binaryType
+ [...] When a RTCDataChannel object is created, the binaryType attribute MUST
+ be initialized to the string "blob".
+
+ 6.2. createDataChannel
+ 4. Let channel have a [[DataChannelLabel]] internal slot initialized to the value of the
+ first argument.
+
+ [ECMA262] 7.1.12. ToString(argument)
+ undefined -> "undefined"
+ null -> "null"
+
+ [WebIDL] 3.10.15. Convert a DOMString to a sequence of Unicode scalar values
+ */
+const labels = [
+ ['"foo"', 'foo', 'foo'],
+ ['null', null, 'null'],
+ ['undefined', undefined, 'undefined'],
+ ['lone surrogate', '\uD800', '\uFFFD'],
+];
+for (const [description, label, expected] of labels) {
+ test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel(label);
+ assert_equals(dc.label, expected);
+ }, `createDataChannel with label ${description} should succeed`);
+}
+
+/*
+ 6.2. RTCDataChannel
+ createDataChannel
+ 11. Let channel have an [[Ordered]] internal slot initialized to option's
+ ordered member.
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', { ordered: false });
+ assert_equals(dc.ordered, false);
+}, 'createDataChannel with ordered false should succeed');
+
+// true as the default value of a boolean is confusing because null is converted
+// to false while undefined is converted to true.
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const dc1 = pc.createDataChannel('', { ordered: null });
+ assert_equals(dc1.ordered, false);
+ const dc2 = pc.createDataChannel('', { ordered: undefined });
+ assert_equals(dc2.ordered, true);
+}, 'createDataChannel with ordered null/undefined should succeed');
+
+/*
+ 6.2. RTCDataChannel
+ createDataChannel
+ 7. Let channel have an [[MaxPacketLifeTime]] internal slot initialized to
+ option's maxPacketLifeTime member, if present, otherwise null.
+ */
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', { maxPacketLifeTime: 0 });
+ assert_equals(dc.maxPacketLifeTime, 0);
+}, 'createDataChannel with maxPacketLifeTime 0 should succeed');
+
+/*
+ 6.2. RTCDataChannel
+ createDataChannel
+ 10. Let channel have an [[MaxRetransmits]] internal slot initialized to
+ option's maxRetransmits member, if present, otherwise null.
+ */
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', { maxRetransmits: 0 });
+ assert_equals(dc.maxRetransmits, 0);
+}, 'createDataChannel with maxRetransmits 0 should succeed');
+
+/*
+ 6.2. createDataChannel
+ 18. If both [[MaxPacketLifeTime]] and [[MaxRetransmits]] attributes are set (not null),
+ throw a TypeError.
+ */
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ pc.createDataChannel('', {
+ maxPacketLifeTime: undefined,
+ maxRetransmits: undefined
+ });
+}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits undefined should succeed');
+
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.createDataChannel('', {
+ maxPacketLifeTime: 0,
+ maxRetransmits: 0
+ }));
+ assert_throws_js(TypeError, () => pc.createDataChannel('', {
+ maxPacketLifeTime: 42,
+ maxRetransmits: 42
+ }));
+}, 'createDataChannel with both maxPacketLifeTime and maxRetransmits should throw TypeError');
+
+/*
+ 6.2. RTCDataChannel
+ createDataChannel
+ 12. Let channel have a [[DataChannelProtocol]] internal slot initialized to option's
+ protocol member.
+ */
+const protocols = [
+ ['"foo"', 'foo', 'foo'],
+ ['null', null, 'null'],
+ ['undefined', undefined, ''],
+ ['lone surrogate', '\uD800', '\uFFFD'],
+];
+for (const [description, protocol, expected] of protocols) {
+ test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', { protocol });
+ assert_equals(dc.protocol, expected);
+ }, `createDataChannel with protocol ${description} should succeed`);
+}
+
+/*
+ 6.2. RTCDataChannel
+ createDataChannel
+ 20. If [[DataChannelId]] is equal to 65535, which is greater than the maximum allowed
+ ID of 65534 but still qualifies as an unsigned short, throw a TypeError.
+ */
+for (const id of [0, 1, 65534]) {
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const dc = pc.createDataChannel('', { id });
+ assert_equals(dc.id, null);
+ }, `createDataChannel with id ${id} and negotiated not set should succeed, but not set the channel's id`);
+}
+
+for (const id of [0, 1]) {
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', { 'negotiated': true, 'id': id });
+ assert_equals(dc.id, id);
+ }, `createDataChannel with id ${id} and negotiated true should succeed, and set the channel's id`);
+}
+
+for (const id of [-1, 65535, 65536]) {
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ assert_throws_js(TypeError, () => pc.createDataChannel('', { id }));
+ }, `createDataChannel with id ${id} and negotiated not set should throw TypeError`);
+}
+
+for (const id of [-1, 65535, 65536]) {
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.createDataChannel('',
+ { 'negotiated': true, 'id': id }));
+ }, `createDataChannel with id ${id} should throw TypeError`);
+}
+
+/*
+ 6.2. createDataChannel
+ 5. If [[DataChannelLabel]] is longer than 65535 bytes, throw a TypeError.
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('l'.repeat(65536)));
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('l'.repeat(65536), {
+ negotiated: true,
+ id: 42
+ }));
+}, 'createDataChannel with too long label should throw TypeError');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('\u00b5'.repeat(32768)));
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('\u00b5'.repeat(32768), {
+ negotiated: true,
+ id: 42
+ }));
+}, 'createDataChannel with too long label (2 byte unicode) should throw TypeError');
+
+/*
+ 6.2. label
+ [...] Scripts are allowed to create multiple RTCDataChannel objects with the same label.
+ [...]
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const label = 'test';
+
+ pc.createDataChannel(label);
+ pc.createDataChannel(label);
+}, 'createDataChannel with same label used twice should not throw');
+
+/*
+ 6.2. createDataChannel
+ 13. If [[DataChannelProtocol]] is longer than 65535 bytes long, throw a TypeError.
+ */
+
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+ const channel = pc.createDataChannel('', { negotiated: true, id: 42 });
+ assert_equals(channel.negotiated, true);
+}, 'createDataChannel with negotiated true and id should succeed');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('', {
+ protocol: 'p'.repeat(65536)
+ }));
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('', {
+ protocol: 'p'.repeat(65536),
+ negotiated: true,
+ id: 42
+ }));
+}, 'createDataChannel with too long protocol should throw TypeError');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('', {
+ protocol: '\u00b6'.repeat(32768)
+ }));
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('', {
+ protocol: '\u00b6'.repeat(32768),
+ negotiated: true,
+ id: 42
+ }));
+}, 'createDataChannel with too long protocol (2 byte unicode) should throw TypeError');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const label = 'l'.repeat(65535);
+ const protocol = 'p'.repeat(65535);
+
+ const dc = pc.createDataChannel(label, {
+ protocol: protocol
+ });
+
+ assert_equals(dc.label, label);
+ assert_equals(dc.protocol, protocol);
+}, 'createDataChannel with maximum length label and protocol should succeed');
+
+/*
+ 6.2 createDataChannel
+ 15. Let channel have an [[DataChannelId]] internal slot initialized to option's id member,
+ if it is present and [[Negotiated]] is true, otherwise null.
+
+ NOTE
+ This means the id member will be ignored if the data channel is negotiated in-band; this
+ is intentional. Data channels negotiated in-band should have IDs selected based on the
+ DTLS role, as specified in [RTCWEB-DATA-PROTOCOL].
+ */
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', {
+ negotiated: false,
+ });
+ assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
+}, 'createDataChannel with negotiated false should succeed');
+
+test(t => {
+ const pc = new RTCPeerConnection;
+ t.add_cleanup(() => pc.close());
+
+ const dc = pc.createDataChannel('', {
+ negotiated: false,
+ id: 42
+ });
+ assert_equals(dc.negotiated, false, 'Expect dc.negotiated to be false');
+ assert_equals(dc.id, null, 'Expect dc.id to be ignored (null)');
+}, 'createDataChannel with negotiated false and id 42 should ignore the id');
+
+/*
+ 6.2. createDataChannel
+ 16. If [[Negotiated]] is true and [[DataChannelId]] is null, throw a TypeError.
+ */
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () =>
+ pc.createDataChannel('test', {
+ negotiated: true
+ }));
+}, 'createDataChannel with negotiated true and id not defined should throw TypeError');
+
+/*
+ 4.4.1.6. Set the RTCSessionSessionDescription
+ 2.2.6. If description is of type "answer" or "pranswer", then run the
+ following steps:
+ 3. If description negotiates the DTLS role of the SCTP transport, and there is an
+ RTCDataChannel with a null id, then generate an ID according to
+ [RTCWEB-DATA-PROTOCOL]. [...]
+
+ 6.1. createDataChannel
+ 21. If the [[DataChannelId]] slot is null (due to no ID being passed into
+ createDataChannel, or [[Negotiated]] being false), and the DTLS role of the SCTP
+ transport has already been negotiated, then initialize [[DataChannelId]] to a value
+ generated by the user agent, according to [RTCWEB-DATA-PROTOCOL], and skip
+ to the next step. If no available ID could be generated, or if the value of the
+ [[DataChannelId]] slot is being used by an existing RTCDataChannel, throw an
+ OperationError exception.
+
+ Note
+ If the [[DataChannelId]] slot is null after this step, it will be populated once
+ the DTLS role is determined during the process of setting an RTCSessionDescription.
+ */
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const negotiatedDc = pc1.createDataChannel('negotiated-channel', {
+ negotiated: true,
+ id: 42,
+ });
+ assert_equals(negotiatedDc.id, 42, 'Expect negotiatedDc.id to be 42');
+
+ const dc1 = pc1.createDataChannel('channel');
+ assert_equals(dc1.id, null, 'Expect initial id to be null');
+
+ const offer = await pc1.createOffer();
+ await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+
+ assert_not_equals(dc1.id, null,
+ 'Expect dc1.id to be assigned after remote description has been set');
+
+ assert_greater_than_equal(dc1.id, 0,
+ 'Expect dc1.id to be set to valid unsigned short');
+
+ assert_less_than(dc1.id, 65535,
+ 'Expect dc1.id to be set to valid unsigned short');
+
+ const dc2 = pc1.createDataChannel('channel');
+
+ assert_not_equals(dc2.id, null,
+ 'Expect dc2.id to be assigned after remote description has been set');
+
+ assert_greater_than_equal(dc2.id, 0,
+ 'Expect dc2.id to be set to valid unsigned short');
+
+ assert_less_than(dc2.id, 65535,
+ 'Expect dc2.id to be set to valid unsigned short');
+
+ assert_not_equals(dc2, dc1,
+ 'Expect channels created from same label to be different');
+
+ assert_equals(dc2.label, dc1.label,
+ 'Expect different channels can have the same label but different id');
+
+ assert_not_equals(dc2.id, dc1.id,
+ 'Expect different channels can have the same label but different id');
+
+ assert_equals(negotiatedDc.id, 42,
+ 'Expect negotiatedDc.id to be 42 after remote description has been set');
+}, 'Channels created (after setRemoteDescription) should have id assigned');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const dc1 = pc.createDataChannel('channel-1', {
+ negotiated: true,
+ id: 42,
+ });
+ assert_equals(dc1.id, 42,
+ 'Expect dc1.id to be 42');
+
+ const dc2 = pc.createDataChannel('channel-2', {
+ negotiated: true,
+ id: 43,
+ });
+ assert_equals(dc2.id, 43,
+ 'Expect dc2.id to be 43');
+
+ assert_throws_dom('OperationError', () =>
+ pc.createDataChannel('channel-3', {
+ negotiated: true,
+ id: 42,
+ }));
+
+}, 'Reusing a data channel id that is in use should throw OperationError');
+
+// We've seen implementations behaving differently before and after the connection has been
+// established.
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel('channel-1', {
+ negotiated: true,
+ id: 42,
+ });
+ assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
+
+ const dc2 = pc1.createDataChannel('channel-2', {
+ negotiated: true,
+ id: 43,
+ });
+ assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
+
+ const offer = await pc1.createOffer();
+ await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(dc1.id, 42, 'Expect dc1.id to be 42');
+
+ assert_equals(dc2.id, 43, 'Expect dc2.id to be 43');
+
+ assert_throws_dom('OperationError', () =>
+ pc1.createDataChannel('channel-3', {
+ negotiated: true,
+ id: 42,
+ }));
+}, 'Reusing a data channel id that is in use (after setRemoteDescription) should throw ' +
+ 'OperationError');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel('channel-1');
+
+ const offer = await pc1.createOffer();
+ await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+
+ assert_not_equals(dc1.id, null,
+ 'Expect dc1.id to be assigned after remote description has been set');
+
+ assert_throws_dom('OperationError', () =>
+ pc1.createDataChannel('channel-2', {
+ negotiated: true,
+ id: dc1.id,
+ }));
+}, 'Reusing a data channel id that is in use (after setRemoteDescription, negotiated via DCEP) ' +
+ 'should throw OperationError');
+
+
+for (const options of [{}, {negotiated: true, id: 0}]) {
+ const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
+
+ // Based on https://bugzilla.mozilla.org/show_bug.cgi?id=1441723
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ await createDataChannelPair(t, options, pc1);
+
+ const dc = pc1.createDataChannel('');
+ assert_equals(dc.readyState, 'connecting', 'Channel should be in the connecting state');
+ }, `New ${mode} should be in the connecting state after creation ` +
+ `(after connection establishment)`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+ pc1.addTrack(audio, stream);
+ pc1.addTrack(video, stream);
+ await createDataChannelPair(t, options, pc1);
+ }, `addTrack, then creating ${mode}, should negotiate properly`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"});
+ t.add_cleanup(() => pc1.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+ pc1.addTrack(audio, stream);
+ pc1.addTrack(video, stream);
+ await createDataChannelPair(t, options, pc1);
+ }, `addTrack, then creating ${mode}, should negotiate properly when max-bundle is used`);
+
+/*
+This test is disabled until https://github.com/w3c/webrtc-pc/issues/2562
+has been resolved; it presupposes that stopping the first transceiver
+breaks the transport.
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection({bundlePolicy: "max-bundle"});
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+ pc1.addTrack(audio, stream);
+ pc1.addTrack(video, stream);
+ const [dc1, dc2] = await createDataChannelPair(t, options, pc1, pc2);
+
+ pc2.getTransceivers()[0].stop();
+ const dc1Closed = new Promise(r => dc1.onclose = r);
+ await exchangeOfferAnswer(pc1, pc2);
+ await dc1Closed;
+ }, `Stopping the bundle-tag when there is a ${mode} in the bundle ` +
+ `should kill the DataChannel`);
+*/
+}
+
+/*
+ Untestable
+ 6.1. createDataChannel
+ 19. If a setting, either [[MaxPacketLifeTime]] or [[MaxRetransmits]], has been set to
+ indicate unreliable mode, and that value exceeds the maximum value supported
+ by the user agent, the value MUST be set to the user agents maximum value.
+
+ 23. Return channel and continue the following steps in parallel.
+ 24. Create channel's associated underlying data transport and configure
+ it according to the relevant properties of channel.
+
+ Tested in RTCPeerConnection-onnegotiationneeded.html
+ 22. If channel is the first RTCDataChannel created on connection, update the
+ negotiation-needed flag for connection.
+
+ Tested in RTCDataChannel-id.html
+ - Odd/even rules for '.id'
+
+ Tested in RTCDataChannel-dcep.html
+ - Transmission of '.label' and further options
+*/
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.createOffer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // countAudioLine()
+ // countVideoLine()
+ // assert_session_desc_similar()
+
+ /*
+ * 4.3.2. createOffer()
+ */
+
+ /*
+ * Final steps to create an offer
+ * 4. Let offer be a newly created RTCSessionDescriptionInit dictionary
+ * with its type member initialized to the string "offer" and its sdp member
+ * initialized to sdpString.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer);
+ assert_equals(pc.currentLocalDescription, null);
+
+ assert_array_equals(states, ['have-local-offer']);
+ }));
+ }, 'createOffer() and then setLocalDescription() should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.close();
+
+ return promise_rejects_dom(t, 'InvalidStateError',
+ pc.createOffer());
+ }, 'createOffer() after connection is closed should reject with InvalidStateError');
+
+ /*
+ * Final steps to create an offer
+ * 2. If connection was modified in such a way that additional inspection of the
+ * system state is necessary, then in parallel begin the steps to create an
+ * offer again, given p, and abort these steps.
+ *
+ * This test might hit step 2 of final steps to create an offer. But the media stream
+ * is likely added already by the time steps to create an offer is executed, because
+ * that is enqueued as an operation.
+ * Either way it verifies that the media stream is included in the offer even though
+ * the stream is added after synchronous call to createOffer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('audio');
+ const promise = pc.createOffer();
+
+ //pc.addTransceiver('audio');
+ return promise.then(offer => {
+ assert_equals(countAudioLine(offer.sdp), 1,
+ 'Expect m=audio line to be found in offer SDP')
+ });
+ }, 'When media stream is added when createOffer() is running in parallel, the result offer should contain the new media stream');
+
+ /*
+ * TODO
+ * 4.3.2 createOffer
+ * 3. If connection is configured with an identity provider, and an identity
+ * assertion has not yet been generated using said identity provider, then
+ * begin the identity assertion request process if it has not already begun.
+ * Steps to create an offer
+ * 1. If the need for an identity assertion was identified when createOffer was
+ * invoked, wait for the identity assertion request process to complete.
+ *
+ * Non-Testable
+ * 4.3.2 createOffer
+ * Steps to create an offer
+ * 4. Inspect the system state to determine the currently available resources as
+ * necessary for generating the offer, as described in [JSEP] (section 4.1.6.).
+ * 5. If this inspection failed for any reason, reject p with a newly created
+ * OperationError and abort these steps.
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const offer = await pc.createOffer();
+
+ assert_equals(pc.pendingLocalDescription, null,
+ 'pendingLocalDescription is null before setLocalDescription');
+ const promise = pc.setLocalDescription(offer);
+ assert_equals(pc.pendingLocalDescription, null,
+ 'pendingLocalDescription is still null while promise pending');
+ await promise;
+ assert_not_equals(pc.pendingLocalDescription, null,
+ 'pendingLocalDescription is not null after await');
+}, "pendingLocalDescription is surfaced at the right time");
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const offer = await pc.createOffer();
+
+ assert_equals(pc.pendingRemoteDescription, null,
+ 'pendingRemoteDescription is null before setRemoteDescription');
+ const promise = pc.setRemoteDescription(offer);
+ assert_equals(pc.pendingRemoteDescription, null,
+ 'pendingRemoteDescription is still null while promise pending');
+ await promise;
+ assert_not_equals(pc.pendingRemoteDescription, null,
+ 'pendingRemoteDescription is not null after await');
+}, "pendingRemoteDescription is surfaced at the right time");
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+
+ assert_equals(pc2.currentLocalDescription, null,
+ 'currentLocalDescription is null before setLocalDescription');
+ const promise = pc2.setLocalDescription(answer);
+ assert_equals(pc2.currentLocalDescription, null,
+ 'currentLocalDescription is still null while promise pending');
+ await promise;
+ assert_not_equals(pc2.currentLocalDescription, null,
+ 'currentLocalDescription is not null after await');
+}, "currentLocalDescription is surfaced at the right time");
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+
+ assert_equals(pc1.currentRemoteDescription, null,
+ 'currentRemoteDescription is null before setRemoteDescription');
+ const promise = pc1.setRemoteDescription(answer);
+ assert_equals(pc1.currentRemoteDescription, null,
+ 'currentRemoteDescription is still null while promise pending');
+ await promise;
+ assert_not_equals(pc1.currentRemoteDescription, null,
+ 'currentRemoteDescription is not null after await');
+}, "currentRemoteDescription is surfaced at the right time");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.iceGatheringState</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+ await pc1.setLocalDescription(await pc1.createOffer({iceRestart: true}));
+ await iceGatheringStateTransitions(pc1, 'gathering', 'complete');
+ expectNoMoreGatheringStateChanges(t, pc1);
+ await pc1.setLocalDescription({type: 'rollback'});
+ await new Promise(r => t.step_timeout(r, 1000));
+}, 'rolling back an ICE restart when gathering is complete should not result in iceGatheringState changes');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('audio', { direction: 'recvonly' });
+ await pc.setLocalDescription(
+ await pc.createOffer());
+ await iceGatheringStateTransitions(pc, 'gathering', 'complete');
+ await pc.setLocalDescription({type: 'rollback'});
+ await iceGatheringStateTransitions(pc, 'new');
+}, 'setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "complete"');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('audio', { direction: 'recvonly' });
+ await pc.setLocalDescription(
+ await pc.createOffer());
+ await iceGatheringStateTransitions(pc, 'gathering');
+ await pc.setLocalDescription({type: 'rollback'});
+ // We might go directly to 'new', or we might go to 'complete' first,
+ // depending on timing. Allow either.
+ const results = await Promise.allSettled([
+ iceGatheringStateTransitions(pc, 'new'),
+ iceGatheringStateTransitions(pc, 'complete', 'new')]);
+ assert_true(results.some(result => result.status == 'fulfilled'),
+ 'ICE gathering state should go back to "new", possibly through "complete"');
+}, 'setLocalDescription(rollback) of original offer should cause iceGatheringState to reach "new" when starting in "gathering"');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>Test RTCPeerConnection.generateCertificate</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170515/webrtc.html
+
+ /*
+ * 4.10. Certificate Management
+ * partial interface RTCPeerConnection {
+ * static Promise<RTCCertificate> generateCertificate(
+ * AlgorithmIdentifier keygenAlgorithm);
+ * };
+ *
+ * 4.10.2. RTCCertificate Interface
+ * interface RTCCertificate {
+ * readonly attribute DOMTimeStamp expires;
+ * ...
+ * };
+ *
+ * [WebCrypto]
+ * 11. Algorithm Dictionary
+ * typedef (object or DOMString) AlgorithmIdentifier;
+ */
+
+ /*
+ * 4.10. The following values must be supported by a user agent:
+ * { name: "RSASSA-PKCS1-v1_5", modulusLength: 2048,
+ * publicExponent: new Uint8Array([1, 0, 1]), hash: "SHA-256" },
+ * and { name: "ECDSA", namedCurve: "P-256" }.
+ */
+ promise_test(t =>
+ RTCPeerConnection.generateCertificate({
+ name: 'RSASSA-PKCS1-v1_5',
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([1, 0, 1]),
+ hash: 'SHA-256'
+ }).then(cert => {
+ assert_true(cert instanceof RTCCertificate,
+ 'Expect cert to be instance of RTCCertificate');
+
+ assert_greater_than(cert.expires, Date.now(),
+ 'Expect generated certificate to expire reasonably long after current time');
+ }),
+ 'generateCertificate() with compulsary RSASSA-PKCS1-v1_5 parameters should succeed');
+
+ promise_test(t =>
+ RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256'
+ }).then(cert => {
+ assert_true(cert instanceof RTCCertificate,
+ 'Expect cert to be instance of RTCCertificate');
+
+ assert_greater_than(cert.expires, Date.now(),
+ 'Expect generated certificate to expire reasonably long after current time');
+ }),
+ 'generateCertificate() with compulsary ECDSA parameters should succeed');
+
+ /*
+ * 4.10. A user agent must reject a call to generateCertificate() with a
+ * DOMException of type NotSupportedError if the keygenAlgorithm
+ * parameter identifies an algorithm that the user agent cannot or
+ * will not use to generate a certificate for RTCPeerConnection.
+ */
+ promise_test(t =>
+ promise_rejects_dom(t, 'NotSupportedError',
+ RTCPeerConnection.generateCertificate('invalid-algo')),
+ 'generateCertificate() with invalid string algorithm should reject with NotSupportedError');
+
+ promise_test(t =>
+ promise_rejects_dom(t, 'NotSupportedError',
+ RTCPeerConnection.generateCertificate({
+ name: 'invalid-algo'
+ })),
+ 'generateCertificate() with invalid algorithm dict should reject with NotSupportedError');
+
+ /*
+ * 4.10.1. Dictionary RTCCertificateExpiration
+ * dictionary RTCCertificateExpiration {
+ * [EnforceRange]
+ * DOMTimeStamp expires;
+ * };
+ *
+ * If this parameter is present it indicates the maximum time that
+ * the RTCCertificate is valid for relative to the current time.
+ *
+ * When generateCertificate is called with an object argument,
+ * the user agent attempts to convert the object into a
+ * RTCCertificateExpiration. If this is unsuccessful, immediately
+ * return a promise that is rejected with a newly created TypeError
+ * and abort processing.
+ */
+
+ promise_test(t => {
+ const start = Date.now();
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256',
+ expires: 2000
+ }).then(cert => {
+ assert_approx_equals(cert.expires, start+2000, 1000);
+ })
+ }, 'generateCertificate() with valid expires parameter should succeed');
+
+ promise_test(t => {
+ return RTCPeerConnection.generateCertificate({
+ name: 'ECDSA',
+ namedCurve: 'P-256',
+ expires: 0
+ }).then(cert => {
+ assert_less_than_equal(cert.expires, Date.now());
+ })
+ }, 'generateCertificate() with 0 expires parameter should generate expired cert');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.getStats</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCStats-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // webrtc-pc 20171130
+ // webrtc-stats 20171122
+
+ // The following helper function is called from RTCPeerConnection-helper.js
+ // getTrackFromUserMedia
+
+ // The following helper function is called from RTCStats-helper.js
+ // validateStatsReport
+ // assert_stats_report_has_stats
+
+ // The following helper function is called from RTCPeerConnection-helper.js
+ // exchangeIceCandidates
+ // exchangeOfferAnswer
+
+ /*
+ 8.2. getStats
+ 1. Let selectorArg be the method's first argument.
+ 2. Let connection be the RTCPeerConnection object on which the method was invoked.
+ 3. If selectorArg is null, let selector be null.
+ 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
+ or RTCRtpReceiver on connection which track member matches selectorArg.
+ If no such sender or receiver exists, or if more than one sender or
+ receiver fit this criteria, return a promise rejected with a newly
+ created InvalidAccessError.
+ 5. Let p be a new promise.
+ 6. Run the following steps in parallel:
+ 1. Gather the stats indicated by selector according to the stats selection algorithm.
+ 2. Resolve p with the resulting RTCStatsReport object, containing the gathered stats.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return pc.getStats();
+ }, 'getStats() with no argument should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return pc.getStats(null);
+ }, 'getStats(null) should succeed');
+
+ /*
+ 8.2. getStats
+ 4. If selectorArg is a MediaStreamTrack let selector be an RTCRtpSender
+ or RTCRtpReceiver on connection which track member matches selectorArg.
+ If no such sender or receiver exists, or if more than one sender or
+ receiver fit this criteria, return a promise rejected with a newly
+ created InvalidAccessError.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return getTrackFromUserMedia('audio')
+ .then(([track, mediaStream]) => {
+ return promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(track));
+ });
+ }, 'getStats() with track not added to connection should reject with InvalidAccessError');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return getTrackFromUserMedia('audio')
+ .then(([track, mediaStream]) => {
+ pc.addTrack(track, mediaStream);
+ return pc.getStats(track);
+ });
+ }, 'getStats() with track added via addTrack should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ pc.addTransceiver(track);
+
+ return pc.getStats(track);
+ }, 'getStats() with track added via addTransceiver should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver1 = pc.addTransceiver('audio');
+
+ // Create another transceiver that resends what
+ // is being received, kind of like echo
+ const transceiver2 = pc.addTransceiver(transceiver1.receiver.track);
+ assert_equals(transceiver1.receiver.track, transceiver2.sender.track);
+
+ return promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(transceiver1.receiver.track));
+ }, 'getStats() with track associated with both sender and receiver should reject with InvalidAccessError');
+
+ /*
+ 8.5. The stats selection algorithm
+ 2. If selector is null, gather stats for the whole connection, add them to result,
+ return result, and abort these steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return pc.getStats()
+ .then(statsReport => {
+ validateStatsReport(statsReport);
+ assert_stats_report_has_stats(statsReport, ['peer-connection']);
+ });
+ }, 'getStats() with no argument should return stats report containing peer-connection stats on an empty PC');
+
+ promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTrack(track, mediaStream);
+ exchangeIceCandidates(pc, pc2);
+ await exchangeOfferAnswer(pc, pc2);
+ await listenToConnected(pc);
+ const statsReport = await pc.getStats();
+ getRequiredStats(statsReport, 'peer-connection');
+ getRequiredStats(statsReport, 'outbound-rtp');
+ }, 'getStats() track with stream returns peer-connection and outbound-rtp stats');
+
+ promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTrack(track);
+ exchangeIceCandidates(pc, pc2);
+ await exchangeOfferAnswer(pc, pc2);
+ await listenToConnected(pc);
+ const statsReport = await pc.getStats();
+ getRequiredStats(statsReport, 'peer-connection');
+ getRequiredStats(statsReport, 'outbound-rtp');
+ }, 'getStats() track without stream returns peer-connection and outbound-rtp stats');
+
+ promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTrack(track, mediaStream);
+ exchangeIceCandidates(pc, pc2);
+ await exchangeOfferAnswer(pc, pc2);
+ await listenToConnected(pc);
+ const statsReport = await pc.getStats();
+ assert_stats_report_has_stats(statsReport, ['outbound-rtp']);
+ }, 'getStats() audio outbound-rtp contains all mandatory stats');
+
+ /*
+ 8.5. The stats selection algorithm
+ 3. If selector is an RTCRtpSender, gather stats for and add the following objects
+ to result:
+ - All RTCOutboundRTPStreamStats objects corresponding to selector.
+ - All stats objects referenced directly or indirectly by the RTCOutboundRTPStreamStats
+ objects added.
+ */
+ promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+
+ let [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTrack(track, mediaStream);
+ exchangeIceCandidates(pc, pc2);
+ await exchangeOfferAnswer(pc, pc2);
+ await listenToConnected(pc);
+ const stats = await pc.getStats(track);
+ getRequiredStats(stats, 'outbound-rtp');
+ }, `getStats() on track associated with RTCRtpSender should return stats report containing outbound-rtp stats`);
+
+ /*
+ 8.5. The stats selection algorithm
+ 4. If selector is an RTCRtpReceiver, gather stats for and add the following objects
+ to result:
+ - All RTCInboundRTPStreamStats objects corresponding to selector.
+ - All stats objects referenced directly or indirectly by the RTCInboundRTPStreamStats
+ added.
+ */
+ promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+
+ let [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTrack(track, mediaStream);
+ exchangeIceCandidates(pc, pc2);
+ await exchangeOfferAnswer(pc, pc2);
+ // Wait for unmute if the track is not already unmuted.
+ // According to spec, it should be muted when being created, but this
+ // is not what this test is testing, so allow it to be unmuted.
+ if (pc2.getReceivers()[0].track.muted) {
+ await new Promise(resolve => {
+ pc2.getReceivers()[0].track.addEventListener('unmute', resolve);
+ });
+ }
+ const stats = await pc2.getStats(pc2.getReceivers()[0].track);
+ getRequiredStats(stats, 'inbound-rtp');
+ }, `getStats() on track associated with RTCRtpReceiver should return stats report containing inbound-rtp stats`);
+
+ /*
+ 8.6 Mandatory To Implement Stats
+ An implementation MUST support generating statistics of the following types
+ when the corresponding objects exist on a PeerConnection, with the attributes
+ that are listed when they are valid for that object.
+ */
+
+ const mandatoryStats = [
+ "codec",
+ "inbound-rtp",
+ "outbound-rtp",
+ "remote-inbound-rtp",
+ "remote-outbound-rtp",
+ "media-source",
+ "peer-connection",
+ "data-channel",
+ "sender",
+ "receiver",
+ "transport",
+ "candidate-pair",
+ "local-candidate",
+ "remote-candidate",
+ "certificate"
+ ];
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc.addTransceiver(track);
+ pc.addTransceiver(track);
+ await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(track));
+ }, `getStats(track) should not work if multiple senders have the same track`);
+
+ promise_test(async t => {
+ const kMinimumTimeElapsedBetweenGetStatsCallsMs = 500;
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const t0 = Math.floor(performance.now());
+ const t0Stats = getRequiredStats(await pc.getStats(), 'peer-connection');
+ await new Promise(
+ r => t.step_timeout(r, kMinimumTimeElapsedBetweenGetStatsCallsMs));
+ const t1Stats = getRequiredStats(await pc.getStats(), 'peer-connection');
+ const t1 = Math.ceil(performance.now());
+ const maximumTimeElapsedBetweenGetStatsCallsMs = t1 - t0;
+ const deltaTimestampMs = t1Stats.timestamp - t0Stats.timestamp;
+ // The delta must be at least the time we waited between calls.
+ assert_greater_than_equal(deltaTimestampMs,
+ kMinimumTimeElapsedBetweenGetStatsCallsMs);
+ // The delta must be at most the time elapsed before the first getStats()
+ // call and after the second getStats() call.
+ assert_less_than_equal(deltaTimestampMs,
+ maximumTimeElapsedBetweenGetStatsCallsMs);
+ }, `RTCStats.timestamp increases with time passing`);
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.getTransceivers</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ /*
+ * 5.1. RTCPeerConnection Interface Extensions
+ * partial interface RTCPeerConnection {
+ * sequence<RTCRtpSender> getSenders();
+ * sequence<RTCRtpReceiver> getReceivers();
+ * sequence<RTCRtpTransceiver> getTransceivers();
+ * ...
+ * };
+ */
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+
+ assert_idl_attribute(pc, 'getSenders');
+ const senders = pc.getSenders();
+ assert_array_equals([], senders, 'Expect senders to be empty array');
+
+ assert_idl_attribute(pc, 'getReceivers');
+ const receivers = pc.getReceivers();
+ assert_array_equals([], receivers, 'Expect receivers to be empty array');
+
+ assert_idl_attribute(pc, 'getTransceivers');
+ const transceivers = pc.getTransceivers();
+ assert_array_equals([], transceivers, 'Expect transceivers to be empty array');
+
+ }, 'Initial peer connection should have list of zero senders, receivers and transceivers');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection-helper tests</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc1.addTransceiver('video');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForState(transceiver.sender.transport, 'connected');
+}, 'Setting up a connection using helpers and defaults should work');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.iceConnectionState - disconnection</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream = await getNoiseStream({audio:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ caller.addTrack(track, stream);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+
+ await listenToIceConnected(caller);
+
+ callee.close();
+ await waitForIceStateChange(caller, ['disconnected', 'failed']);
+ // TODO: this should eventually transition to failed but that takes
+ // somewhat long (15-30s) so is not testable.
+ }, 'ICE goes to disconnected if the other side goes away');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.iceConnectionState</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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
+
+ /*
+ 4.3.2. Interface Definition
+ interface RTCPeerConnection : EventTarget {
+ ...
+ readonly attribute RTCIceConnectionState iceConnectionState;
+ attribute EventHandler oniceconnectionstatechange;
+ };
+
+ 4.4.4 RTCIceConnectionState Enum
+ enum RTCIceConnectionState {
+ "new",
+ "checking",
+ "connected",
+ "completed",
+ "failed",
+ "disconnected",
+ "closed"
+ };
+
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceTransportState state;
+ attribute EventHandler onstatechange;
+
+ ...
+ };
+
+ enum RTCIceTransportState {
+ "new",
+ "checking",
+ "connected",
+ "completed",
+ "failed",
+ "disconnected",
+ "closed"
+ };
+ */
+
+ /*
+ 4.4.4 RTCIceConnectionState Enum
+ new
+ Any of the RTCIceTransports are in the new state and none of them
+ are in the checking, failed or disconnected state, or all
+ RTCIceTransport s are in the closed state.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ assert_equals(pc.iceConnectionState, 'new');
+ }, 'Initial iceConnectionState should be new');
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ pc.close();
+ assert_equals(pc.iceConnectionState, 'closed');
+ }, 'Closing the connection should set iceConnectionState to closed');
+
+ /*
+ 4.4.4 RTCIceConnectionState Enum
+ checking
+ Any of the RTCIceTransport s are in the checking state and none of
+ them are in the failed or disconnected state.
+
+ connected
+ All RTCIceTransport s are in the connected, completed or closed state
+ and at least one of them is in the connected state.
+
+ completed
+ All RTCIceTransport s are in the completed or closed state and at least
+ one of them is in the completed state.
+
+ checking
+ The RTCIceTransport has received at least one remote candidate and
+ is checking candidate pairs and has either not yet found a connection
+ or consent checks [RFC7675] have failed on all previously successful
+ candidate pairs. In addition to checking, it may also still be gathering.
+
+ 5.6. enum RTCIceTransportState
+ connected
+ The RTCIceTransport has found a usable connection, but is still
+ checking other candidate pairs to see if there is a better connection.
+ It may also still be gathering and/or waiting for additional remote
+ candidates. If consent checks [RFC7675] fail on the connection in use,
+ and there are no other successful candidate pairs available, then the
+ state transitions to "checking" (if there are candidate pairs remaining
+ to be checked) or "disconnected" (if there are no candidate pairs to
+ check, but the peer is still gathering and/or waiting for additional
+ remote candidates).
+
+ completed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate
+ pairs and found a connection. If consent checks [RFC7675] subsequently
+ fail on all successful candidate pairs, the state transitions to "failed".
+ */
+ async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ let had_checking = false;
+
+ const onIceConnectionStateChange = t.step_func(() => {
+ const {iceConnectionState} = pc1;
+ if (iceConnectionState === 'checking') {
+ had_checking = true;
+ } else if (iceConnectionState === 'connected' ||
+ iceConnectionState === 'completed') {
+ assert_true(had_checking, 'state should pass checking before' +
+ ' reaching connected or completed');
+ t.done();
+ } else if (iceConnectionState === 'failed') {
+ assert_unreached("ICE should not fail");
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have connected or ' +
+ 'completed connection state');
+
+async_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ const onIceConnectionStateChange = t.step_func(() => {
+ const { iceConnectionState } = pc1;
+
+ if(iceConnectionState === 'checking') {
+ const iceTransport = pc1.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.state, 'checking',
+ 'Expect ICE transport to be in checking state when' +
+ ' iceConnectionState is checking');
+
+ } else if(iceConnectionState === 'connected') {
+ const iceTransport = pc1.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.state, 'connected',
+ 'Expect ICE transport to be in connected state when' +
+ ' iceConnectionState is connected');
+ t.done();
+ } else if(iceConnectionState === 'completed') {
+ const iceTransport = pc1.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.state, 'completed',
+ 'Expect ICE transport to be in connected state when' +
+ ' iceConnectionState is completed');
+ t.done();
+ } else if (iceConnectionState === 'failed') {
+ assert_unreached("ICE should not fail");
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ assert_equals(pc1.oniceconnectionstatechange, null,
+ 'Expect connection to have iceconnectionstatechange event');
+
+ pc1.addEventListener('iceconnectionstatechange', onIceConnectionStateChange);
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually ' +
+ 'have connected connection state');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc1);
+ }, 'connection with audio track should eventually ' +
+ 'have connected connection state');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true, video:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc1);
+ }, 'connection with audio and video tracks should eventually ' +
+ 'have connected connection state');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ caller.addTransceiver('audio', {direction:'recvonly'});
+ const stream = await getNoiseStream({audio:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ callee.addTrack(track, stream);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+
+ assert_equals(caller.getTransceivers().length, 1);
+ const [transceiver] = caller.getTransceivers();
+ assert_equals(transceiver.currentDirection, 'recvonly');
+
+ await listenToIceConnected(caller);
+ }, 'ICE can connect in a recvonly usecase');
+
+ /*
+ TODO
+ 4.4.4 RTCIceConnectionState Enum
+ failed
+ Any of the RTCIceTransport s are in the failed state.
+
+ disconnected
+ Any of the RTCIceTransport s are in the disconnected state and none of
+ them are in the failed state.
+
+ closed
+ The RTCPeerConnection object's [[ isClosed]] slot is true.
+
+ 5.6. enum RTCIceTransportState
+ new
+ The RTCIceTransport is gathering candidates and/or waiting for
+ remote candidates to be supplied, and has not yet started checking.
+
+ failed
+ The RTCIceTransport has finished gathering, received an indication that
+ there are no more remote candidates, finished checking all candidate pairs,
+ and all pairs have either failed connectivity checks or have lost consent.
+
+ disconnected
+ The ICE Agent has determined that connectivity is currently lost for this
+ RTCIceTransport . This is more aggressive than failed, and may trigger
+ intermittently (and resolve itself without action) on a flaky network.
+ The way this state is determined is implementation dependent.
+
+ Examples include:
+ Losing the network interface for the connection in use.
+ Repeatedly failing to receive a response to STUN requests.
+
+ Alternatively, the RTCIceTransport has finished checking all existing
+ candidates pairs and failed to find a connection (or consent checks
+ [RFC7675] once successful, have now failed), but it is still gathering
+ and/or waiting for additional remote candidates.
+
+ closed
+ The RTCIceTransport has shut down and is no longer responding to STUN requests.
+ */
+
+for (let bundle_policy of ['balanced', 'max-bundle', 'max-compat']) {
+
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
+ t.add_cleanup(() => caller.close());
+ const stream = await getNoiseStream(
+ {audio: true, video:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track1, track2] = stream.getTracks();
+ const sender1 = caller.addTrack(track1);
+ const sender2 = caller.addTrack(track2);
+ caller.createDataChannel('datachannel');
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ exchangeIceCandidates(caller, callee);
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
+ assert_equals(sender1.transport, caller_transceiver1.sender.transport);
+ await callee.setRemoteDescription(offer);
+ const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ // At this point, we should have a single ICE transport, and it
+ // should eventually get to the "connected" state.
+ await waitForState(caller_transceiver1.receiver.transport.iceTransport,
+ 'connected');
+ // The PeerConnection's iceConnectionState should therefore be 'connected'
+ assert_equals(caller.iceConnectionState, 'connected',
+ 'PC.iceConnectionState:');
+ }, 'iceConnectionState changes at the right time, with bundle policy ' +
+ bundle_policy);
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
+ pc1.candidateBuffer = [];
+ pc2.onicecandidate = e => {
+ // Don't add candidate if candidate buffer is already used
+ if (pc1.candidateBuffer) {
+ pc1.candidateBuffer.push(e.candidate)
+ }
+ };
+ pc1.iceStates = [pc1.iceConnectionState];
+ pc2.iceStates = [pc2.iceConnectionState];
+ pc1.oniceconnectionstatechange = () => {
+ pc1.iceStates.push(pc1.iceConnectionState);
+ };
+ pc2.oniceconnectionstatechange = () => {
+ pc2.iceStates.push(pc2.iceConnectionState);
+ };
+
+ const localStream = await getNoiseStream({audio: true, video: true});
+ const localStream2 = await getNoiseStream({audio: true, video: true});
+ const remoteStream = await getNoiseStream({audio: true, video: true});
+ for (const stream of [localStream, localStream2, remoteStream]) {
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ }
+ localStream.getTracks().forEach(t => pc1.addTrack(t, localStream));
+ localStream2.getTracks().forEach(t => pc1.addTrack(t, localStream2));
+ remoteStream.getTracks().forEach(t => pc2.addTrack(t, remoteStream));
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ pc1.candidateBuffer.forEach(c => pc1.addIceCandidate(c));
+ delete pc1.candidateBuffer;
+ await listenToIceConnected(pc1);
+ await listenToIceConnected(pc2);
+ // While we're waiting for pc2, pc1 may or may not have transitioned
+ // to "completed" state, so allow for both cases.
+ if (pc1.iceStates.length == 3) {
+ assert_array_equals(pc1.iceStates, ['new', 'checking', 'connected']);
+ } else {
+ assert_array_equals(pc1.iceStates, ['new', 'checking', 'connected',
+ 'completed']);
+ }
+ assert_array_equals(pc2.iceStates, ['new', 'checking', 'connected']);
+}, 'Responder ICE connection state behaves as expected');
+
+/*
+ Test case for step 11 of PeerConnection.close().
+ ...
+ 11. Set connection's ICE connection state to "closed". This does not invoke
+ the "update the ICE connection state" procedure, and does not fire any
+ event.
+ ...
+*/
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc2);
+
+ pc2.oniceconnectionstatechange = t.unreached_func();
+ pc2.close();
+ assert_equals(pc2.iceConnectionState, 'closed');
+ await new Promise(r => t.step_timeout(r, 100));
+}, 'Closing a PeerConnection should not fire iceconnectionstatechange event');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.iceGatheringState</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // exchangeAnswer
+ // exchangeIceCandidates
+ // generateAudioReceiveOnlyOffer
+
+ /*
+ 4.3.2. Interface Definition
+ interface RTCPeerConnection : EventTarget {
+ ...
+ readonly attribute RTCIceGatheringState iceGatheringState;
+ attribute EventHandler onicegatheringstatechange;
+ };
+
+ 4.4.2. RTCIceGatheringState Enum
+ enum RTCIceGatheringState {
+ "new",
+ "gathering",
+ "complete"
+ };
+
+ 5.6. RTCIceTransport Interface
+ interface RTCIceTransport {
+ readonly attribute RTCIceGathererState gatheringState;
+ ...
+ };
+
+ enum RTCIceGathererState {
+ "new",
+ "gathering",
+ "complete"
+ };
+ */
+
+ /*
+ 4.4.2. RTCIceGatheringState Enum
+ new
+ Any of the RTCIceTransport s are in the new gathering state and
+ none of the transports are in the gathering state, or there are
+ no transports.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.iceGatheringState, 'new');
+ }, 'Initial iceGatheringState should be new');
+
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ let reachedGathering = false;
+ const onIceGatheringStateChange = t.step_func(() => {
+ const { iceGatheringState } = pc;
+
+ if(iceGatheringState === 'gathering') {
+ reachedGathering = true;
+ } else if(iceGatheringState === 'complete') {
+ assert_true(reachedGathering, 'iceGatheringState should reach gathering before complete');
+ t.done();
+ }
+ });
+
+ assert_equals(pc.onicegatheringstatechange, null,
+ 'Expect connection to have icegatheringstatechange event');
+ assert_equals(pc.iceGatheringState, 'new');
+
+ pc.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
+
+ generateAudioReceiveOnlyOffer(pc)
+ .then(offer => pc.setLocalDescription(offer))
+ .then(err => t.step_func(err =>
+ assert_unreached(`Unhandled rejection ${err.name}: ${err.message}`)));
+ }, 'iceGatheringState should eventually become complete after setLocalDescription');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+
+ expectNoMoreGatheringStateChanges(t, pc1);
+ expectNoMoreGatheringStateChanges(t, pc2);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setLocalDescription(await pc2.createOffer());
+
+ await new Promise(r => t.step_timeout(r, 500));
+ }, 'setLocalDescription(reoffer) with no new transports should not cause iceGatheringState to change');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ expectNoMoreGatheringStateChanges(t, pc1);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+
+ await new Promise(r => t.step_timeout(r, 500));
+ }, 'setLocalDescription() with no transports should not cause iceGatheringState to change');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+ await pc1.setLocalDescription(await pc1.createOffer({iceRestart: true}));
+ await iceGatheringStateTransitions(pc1, 'gathering', 'complete');
+ }, 'setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to "checking" and then "complete"');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ expectNoMoreGatheringStateChanges(t, pc2);
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ await pc2.setRemoteDescription({type: 'rollback'});
+ await pc2.setRemoteDescription(offer);
+ }, 'sRD does not cause ICE gathering state changes');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await initialOfferAnswerWithIceGatheringStateTransitions(
+ pc1, pc2);
+
+ const pc1waiter = iceGatheringStateTransitions(pc1, 'new');
+ const pc2waiter = iceGatheringStateTransitions(pc2, 'new');
+ pc1.getTransceivers()[0].stop();
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ assert_equals(pc2.getTransceivers().length, 0,
+ 'PC2 transceivers should be invisible after negotiation');
+ assert_equals(pc2.iceGatheringState, 'new');
+ await pc2waiter;
+ await pc1.setRemoteDescription(pc2.localDescription);
+ assert_equals(pc1.getTransceivers().length, 0,
+ 'PC1 transceivers should be invisible after negotiation');
+ assert_equals(pc1.iceGatheringState, 'new');
+ await pc1waiter;
+ }, 'renegotiation that closes all transports should result in ICE gathering state "new"');
+
+ /*
+ 4.3.2. RTCIceGatheringState Enum
+ new
+ Any of the RTCIceTransports are in the "new" gathering state and none
+ of the transports are in the "gathering" state, or there are no
+ transports.
+
+ gathering
+ Any of the RTCIceTransport s are in the gathering state.
+
+ complete
+ At least one RTCIceTransport exists, and all RTCIceTransports are
+ in the completed gathering state.
+
+ 5.6. RTCIceGathererState
+ gathering
+ The RTCIceTransport is in the process of gathering candidates.
+
+ complete
+ The RTCIceTransport has completed gathering and the end-of-candidates
+ indication for this transport has been sent. It will not gather candidates
+ again until an ICE restart causes it to restart.
+ */
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ const onIceGatheringStateChange = t.step_func(() => {
+ const { iceGatheringState } = pc2;
+
+ if(iceGatheringState === 'gathering') {
+ const iceTransport = pc2.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.gatheringState, 'gathering',
+ 'Expect ICE transport to be in gathering gatheringState when iceGatheringState is gathering');
+
+ } else if(iceGatheringState === 'complete') {
+ const iceTransport = pc2.sctp.transport.iceTransport;
+
+ assert_equals(iceTransport.gatheringState, 'complete',
+ 'Expect ICE transport to be in complete gatheringState when iceGatheringState is complete');
+
+ t.done();
+ }
+ });
+
+ pc1.createDataChannel('test');
+
+ // Spec bug w3c/webrtc-pc#1382
+ // Because sctp is only defined when answer is set, we listen
+ // to pc2 so that we can be confident that sctp is defined
+ // when icegatheringstatechange event is fired.
+ pc2.addEventListener('icegatheringstatechange', onIceGatheringStateChange);
+
+
+ exchangeIceCandidates(pc1, pc2);
+
+ await pc1.setLocalDescription();
+ assert_equals(pc1.sctp.transport.iceTransport.gatheringState, 'new');
+ await pc2.setRemoteDescription(pc1.localDescription);
+
+ await exchangeAnswer(pc1, pc2);
+ }, 'connection with one data channel should eventually have connected connection state');
+
+ /*
+ TODO
+ 5.6. RTCIceTransport Interface
+ new
+ The RTCIceTransport was just created, and has not started gathering
+ candidates yet.
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>Mandatory-to-implement stats compliance (a subset of webrtc-stats)</title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCStats-helper.js"></script>
+<script>
+'use strict';
+
+// From https://w3c.github.io/webrtc-pc/#mandatory-to-implement-stats
+
+const mandatory = {
+ RTCRtpStreamStats: [
+ "ssrc",
+ "kind",
+ "transportId",
+ "codecId",
+ ],
+ RTCReceivedRtpStreamStats: [
+ "packetsReceived",
+ "packetsLost",
+ "jitter",
+ "framesDropped"
+ ],
+ RTCInboundRtpStreamStats: [
+ "remoteId",
+ "framesDecoded",
+ "nackCount",
+ "framesReceived",
+ "bytesReceived",
+ "totalAudioEnergy",
+ "totalSamplesDuration",
+ "packetsDiscarded"
+ ],
+ RTCRemoteInboundRtpStreamStats: [
+ "localId",
+ "roundTripTime",
+ ],
+ RTCSentRtpStreamStats: [
+ "packetsSent",
+ "bytesSent"
+ ],
+ RTCOutboundRtpStreamStats: [
+ "remoteId",
+ "framesEncoded",
+ "nackCount",
+ "framesSent"
+ ],
+ RTCRemoteOutboundRtpStreamStats: [
+ "localId",
+ "remoteTimestamp",
+ ],
+ RTCPeerConnectionStats: [
+ "dataChannelsOpened",
+ "dataChannelsClosed",
+ ],
+ RTCDataChannelStats: [
+ "label",
+ "protocol",
+ "dataChannelIdentifier",
+ "state",
+ "messagesSent",
+ "bytesSent",
+ "messagesReceived",
+ "bytesReceived",
+ ],
+ RTCMediaSourceStats: [
+ "trackIdentifier",
+ "kind"
+ ],
+ RTCAudioSourceStats: [
+ "totalAudioEnergy",
+ "totalSamplesDuration"
+ ],
+ RTCVideoSourceStats: [
+ "width",
+ "height",
+ "framesPerSecond"
+ ],
+ RTCCodecStats: [
+ "payloadType",
+ /* codecType is part of MTI but is not systematically set
+ per https://www.w3.org/TR/webrtc-stats/#dom-rtccodecstats-codectype
+ If the dictionary member is not present, it means that
+ this media format can be both encoded and decoded. */
+ // "codecType",
+ "mimeType",
+ "clockRate",
+ "channels",
+ "sdpFmtpLine",
+ ],
+ RTCTransportStats: [
+ "bytesSent",
+ "bytesReceived",
+ "selectedCandidatePairId",
+ "localCertificateId",
+ "remoteCertificateId",
+ ],
+ RTCIceCandidatePairStats: [
+ "transportId",
+ "localCandidateId",
+ "remoteCandidateId",
+ "state",
+ "nominated",
+ "bytesSent",
+ "bytesReceived",
+ "totalRoundTripTime",
+ "currentRoundTripTime"
+ ],
+ RTCIceCandidateStats: [
+ "address",
+ "port",
+ "protocol",
+ "candidateType",
+ ],
+ RTCCertificateStats: [
+ "fingerprint",
+ "fingerprintAlgorithm",
+ "base64Certificate",
+ /* issuerCertificateId is part of MTI but is not systematically set
+ per https://www.w3.org/TR/webrtc-stats/#dom-rtccertificatestats-issuercertificateid
+ If the current certificate is at the end of the chain
+ (i.e. a self-signed certificate), this will not be set. */
+ // "issuerCertificateId",
+ ],
+};
+
+// From https://w3c.github.io/webrtc-stats/webrtc-stats.html#rtcstatstype-str*
+
+const dictionaryNames = {
+ "codec": "RTCCodecStats",
+ "inbound-rtp": "RTCInboundRtpStreamStats",
+ "outbound-rtp": "RTCOutboundRtpStreamStats",
+ "remote-inbound-rtp": "RTCRemoteInboundRtpStreamStats",
+ "remote-outbound-rtp": "RTCRemoteOutboundRtpStreamStats",
+ "csrc": "RTCRtpContributingSourceStats",
+ "peer-connection": "RTCPeerConnectionStats",
+ "data-channel": "RTCDataChannelStats",
+ "media-source": {
+ audio: "RTCAudioSourceStats",
+ video: "RTCVideoSourceStats"
+ },
+ "track": {
+ video: "RTCSenderVideoTrackAttachmentStats",
+ audio: "RTCSenderAudioTrackAttachmentStats"
+ },
+ "sender": {
+ audio: "RTCAudioSenderStats",
+ video: "RTCVideoSenderStats"
+ },
+ "receiver": {
+ audio: "RTCAudioReceiverStats",
+ video: "RTCVideoReceiverStats",
+ },
+ "transport": "RTCTransportStats",
+ "candidate-pair": "RTCIceCandidatePairStats",
+ "local-candidate": "RTCIceCandidateStats",
+ "remote-candidate": "RTCIceCandidateStats",
+ "certificate": "RTCCertificateStats",
+};
+
+// From https://w3c.github.io/webrtc-stats/webrtc-stats.html (webidl)
+
+const parents = {
+ RTCVideoSourceStats: "RTCMediaSourceStats",
+ RTCAudioSourceStats: "RTCMediaSourceStats",
+ RTCReceivedRtpStreamStats: "RTCRtpStreamStats",
+ RTCInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
+ RTCRemoteInboundRtpStreamStats: "RTCReceivedRtpStreamStats",
+ RTCSentRtpStreamStats: "RTCRtpStreamStats",
+ RTCOutboundRtpStreamStats: "RTCSentRtpStreamStats",
+ RTCRemoteOutboundRtpStreamStats : "RTCSentRtpStreamStats",
+};
+
+const remaining = JSON.parse(JSON.stringify(mandatory));
+for (const dictName in remaining) {
+ remaining[dictName] = new Set(remaining[dictName]);
+}
+
+async function getAllStats(t, pc) {
+ // Try to obtain as many stats as possible, waiting up to 20 seconds for
+ // roundTripTime which can take several RTCP messages to calculate.
+ let stats;
+ for (let i = 0; i < 20; i++) {
+ stats = await pc.getStats();
+ const values = [...stats.values()];
+ const [audio, video] = ["audio", "video"].map(kind =>
+ values.find(s => s.type == "remote-inbound-rtp" && s.kind == kind));
+ if (audio && "roundTripTime" in audio &&
+ video && "roundTripTime" in video) {
+ return stats;
+ }
+ await new Promise(r => t.step_timeout(r, 1000));
+ }
+ return stats;
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel("dummy", {negotiated: true, id: 0});
+ const dc2 = pc2.createDataChannel("dummy", {negotiated: true, id: 0});
+
+ const stream = await getNoiseStream({video: true, audio:true});
+ for (const track of stream.getTracks()) {
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+ t.add_cleanup(() => track.stop());
+ }
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ const stats = await getAllStats(t, pc1);
+
+ // The focus of this test is not API correctness, but rather to provide an
+ // accessible metric of implementation progress by dictionary member. We count
+ // whether we've seen each dictionary's mandatory members in getStats().
+
+ test(t => {
+ for (const stat of stats.values()) {
+ let dictName = dictionaryNames[stat.type];
+ if (!dictName) continue;
+ if (typeof dictName == "object") {
+ dictName = dictName[stat.kind];
+ }
+
+ assert_equals(typeof dictName, "string", "Test error. String.");
+ if (dictName && mandatory[dictName]) {
+ do {
+ const memberNames = mandatory[dictName];
+ const remainingNames = remaining[dictName];
+ assert_true(memberNames.length > 0, "Test error. Parent not found.");
+ for (const memberName of memberNames) {
+ if (memberName in stat) {
+ assert_not_equals(stat[memberName], undefined, "Not undefined");
+ remainingNames.delete(memberName);
+ }
+ }
+ dictName = parents[dictName];
+ } while (dictName);
+ }
+ }
+ }, "Validating stats");
+
+ for (const dictName in mandatory) {
+ for (const memberName of mandatory[dictName]) {
+ test(t => {
+ assert_true(!remaining[dictName].has(memberName),
+ `Is ${memberName} present`);
+ }, `${dictName}'s ${memberName}`);
+ }
+ }
+}, 'getStats succeeds');
+
+</script>
\ No newline at end of file
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.ondatachannel</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// exchangeIceCandidates
+// exchangeOfferAnswer
+// createDataChannelPair
+
+/*
+ 6.2. RTCDataChannel
+ When an underlying data transport is to be announced (the other peer created a channel with
+ negotiated unset or set to false), the user agent of the peer that did not initiate the
+ creation process MUST queue a task to run the following steps:
+ 2. Let channel be a newly created RTCDataChannel object.
+ 7. Set channel's [[ReadyState]] to open (but do not fire the open event, yet).
+ 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
+
+ 6.3. RTCDataChannelEvent
+ Firing a datachannel event named e with an RTCDataChannel channel means that an event with the
+ name e, which does not bubble (except where otherwise stated) and is not cancelable (except
+ where otherwise stated), and which uses the RTCDataChannelEvent interface with the channel
+ attribute set to channel, MUST be created and dispatched at the given target.
+
+ interface RTCDataChannelEvent : Event {
+ readonly attribute RTCDataChannel channel;
+ };
+ */
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ let eventCount = 0;
+
+ pc2.ondatachannel = t.step_func((event) => {
+ eventCount++;
+ assert_equals(eventCount, 1,
+ 'Expect data channel event to fire exactly once');
+
+ assert_true(event instanceof RTCDataChannelEvent,
+ 'Expect event to be instance of RTCDataChannelEvent');
+
+ assert_equals(event.bubbles, false);
+ assert_equals(event.cancelable, false);
+
+ const dc = event.channel;
+ assert_true(dc instanceof RTCDataChannel,
+ 'Expect channel to be instance of RTCDataChannel');
+
+ // The channel should be in the 'open' state already.
+ // See: https://github.com/w3c/webrtc-pc/pull/1851
+ assert_equals(dc.readyState, 'open',
+ 'Expect channel ready state to be open');
+
+ resolver.resolve();
+ });
+
+ pc1.createDataChannel('fire-me!');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'Data channel event should fire when new data channel is announced to the remote peer');
+
+/*
+ Since the channel should be in the 'open' state when dispatching via the 'datachannel' event,
+ we should be able to send data in the event handler.
+ */
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const message = 'meow meow!';
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc2 = event.channel;
+ dc2.send(message);
+ });
+
+ const dc1 = pc1.createDataChannel('fire-me!');
+ dc1.onmessage = t.step_func((event) => {
+ assert_equals(event.data, message,
+ 'Received data should be equal to sent data');
+
+ resolver.resolve();
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'Should be able to send data in a datachannel event handler');
+
+/*
+ 6.2. RTCDataChannel
+ When an underlying data transport is to be announced (the other peer created a channel with
+ negotiated unset or set to false), the user agent of the peer that did not initiate the
+ creation process MUST queue a task to run the following steps:
+ 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
+ 9. If the channel's [[ReadyState]] is still open, announce the data channel as open.
+ */
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc = event.channel;
+ dc.onopen = t.step_func(() => {
+ assert_unreached('Open event should not fire');
+ });
+
+ // This should prevent triggering the 'open' event
+ dc.close();
+
+ // Wait a bit to ensure the 'open' event does NOT fire
+ t.step_timeout(() => resolver.resolve(), 500);
+ });
+
+ pc1.createDataChannel('fire-me!');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'Open event should not be raised when closing the channel in the datachannel event');
+
+// Added this test as a result of the discussion in
+// https://github.com/w3c/webrtc-pc/pull/1851#discussion_r185976747
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc = event.channel;
+ dc.onopen = t.step_func((event) => {
+ resolver.resolve();
+ });
+
+ // This should NOT prevent triggering the 'open' event since it enqueues at least two tasks
+ t.step_timeout(() => {
+ t.step_timeout(() => {
+ dc.close()
+ }, 1);
+ }, 1);
+ });
+
+ pc1.createDataChannel('fire-me!');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'Open event should be raised when closing the channel in the datachannel event after ' +
+ 'enqueuing a task');
+
+
+/*
+ Combination of the two tests above (send and close).
+ */
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const message = 'meow meow!';
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc2 = event.channel;
+ dc2.onopen = t.step_func(() => {
+ assert_unreached('Open event should not fire');
+ });
+
+ // This should send but still prevent triggering the 'open' event
+ dc2.send(message);
+ dc2.close();
+ });
+
+ const dc1 = pc1.createDataChannel('fire-me!');
+ dc1.onmessage = t.step_func((event) => {
+ assert_equals(event.data, message,
+ 'Received data should be equal to sent data');
+
+ resolver.resolve();
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'Open event should not be raised when sending and immediately closing the channel in the ' +
+ 'datachannel event');
+
+/*
+ 6.2. RTCDataChannel
+
+ interface RTCDataChannel : EventTarget {
+ readonly attribute USVString label;
+ readonly attribute boolean ordered;
+ readonly attribute unsigned short? maxPacketLifeTime;
+ readonly attribute unsigned short? maxRetransmits;
+ readonly attribute USVString protocol;
+ readonly attribute boolean negotiated;
+ readonly attribute unsigned short? id;
+ readonly attribute RTCDataChannelState readyState;
+ ...
+ };
+
+ When an underlying data transport is to be announced (the other peer created a channel with
+ negotiated unset or set to false), the user agent of the peer that did not initiate the
+ creation process MUST queue a task to run the following steps:
+ 2. Let channel be a newly created RTCDataChannel object.
+ 3. Let configuration be an information bundle received from the other peer as a part of the
+ process to establish the underlying data transport described by the WebRTC DataChannel
+ Protocol specification [RTCWEB-DATA-PROTOCOL].
+ 4. Initialize channel's [[DataChannelLabel]], [[Ordered]], [[MaxPacketLifeTime]],
+ [[MaxRetransmits]], [[DataChannelProtocol]], and [[DataChannelId]] internal slots to the
+ corresponding values in configuration.
+ 5. Initialize channel's [[Negotiated]] internal slot to false.
+ 7. Set channel's [[ReadyState]] slot to connecting.
+ 8. Fire a datachannel event named datachannel with channel at the RTCPeerConnection object.
+
+ Note: More exhaustive tests are defined in RTCDataChannel-dcep
+ */
+
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel('test', {
+ ordered: false,
+ maxRetransmits: 1,
+ protocol: 'custom'
+ });
+
+ assert_equals(dc1.label, 'test');
+ assert_equals(dc1.ordered, false);
+ assert_equals(dc1.maxPacketLifeTime, null);
+ assert_equals(dc1.maxRetransmits, 1);
+ assert_equals(dc1.protocol, 'custom');
+ assert_equals(dc1.negotiated, false);
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc2 = event.channel;
+ assert_true(dc2 instanceof RTCDataChannel,
+ 'Expect channel to be instance of RTCDataChannel');
+
+ assert_equals(dc2.label, 'test');
+ assert_equals(dc2.ordered, false);
+ assert_equals(dc2.maxPacketLifeTime, null);
+ assert_equals(dc2.maxRetransmits, 1);
+ assert_equals(dc2.protocol, 'custom');
+ assert_equals(dc2.negotiated, false);
+ assert_equals(dc2.id, dc1.id);
+
+ resolver.resolve();
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'In-band negotiated channel created on remote peer should match the same configuration as local ' +
+ 'peer');
+
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const dc1 = pc1.createDataChannel('');
+
+ assert_equals(dc1.label, '');
+ assert_equals(dc1.ordered, true);
+ assert_equals(dc1.maxPacketLifeTime, null);
+ assert_equals(dc1.maxRetransmits, null);
+ assert_equals(dc1.protocol, '');
+ assert_equals(dc1.negotiated, false);
+
+ pc2.ondatachannel = t.step_func((event) => {
+ const dc2 = event.channel;
+ assert_true(dc2 instanceof RTCDataChannel,
+ 'Expect channel to be instance of RTCDataChannel');
+
+ assert_equals(dc2.label, '');
+ assert_equals(dc2.ordered, true);
+ assert_equals(dc2.maxPacketLifeTime, null);
+ assert_equals(dc2.maxRetransmits, null);
+ assert_equals(dc2.protocol, '');
+ assert_equals(dc2.negotiated, false);
+ assert_equals(dc2.id, dc1.id);
+
+ resolver.resolve();
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ await resolver;
+}, 'In-band negotiated channel created on remote peer should match the same (default) ' +
+ 'configuration as local peer');
+
+/*
+ 6.2. RTCDataChannel
+ Dictionary RTCDataChannelInit Members
+ negotiated
+ The default value of false tells the user agent to announce the
+ channel in-band and instruct the other peer to dispatch a corresponding
+ RTCDataChannel object. If set to true, it is up to the application
+ to negotiate the channel and create a RTCDataChannel object with the
+ same id at the other peer.
+ */
+promise_test(async (t) => {
+ const resolver = new Resolver();
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc2.ondatachannel = t.unreached_func('datachannel event should not be fired');
+
+ pc1.createDataChannel('test', {
+ negotiated: true,
+ id: 42
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ // Wait a bit to ensure the 'datachannel' event does NOT fire
+ t.step_timeout(() => resolver.resolve(), 500);
+ await resolver;
+}, 'Negotiated channel should not fire datachannel event on remote peer');
+
+/*
+ Non-testable
+ 6.2. RTCDataChannel
+ When an underlying data transport is to be announced
+ 1. If the associated RTCPeerConnection object's [[isClosed]] slot
+ is true, abort these steps.
+
+ The above step is not testable because to reach it we would have to
+ close the peer connection just between receiving the in-band negotiated data
+ channel via DCEP and firing the datachannel event.
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.onicecandidateerror</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+
+promise_test(async t => {
+ const config = {
+ iceServers: [{urls: "turn:123", username: "123", credential: "123"}]
+ };
+ const pc = new RTCPeerConnection(config);
+ t.add_cleanup(() => pc.close());
+ const onErrorPromise = addEventListenerPromise(t, pc, 'icecandidateerror', event => {
+ assert_true(event instanceof RTCPeerConnectionIceErrorEvent,
+ 'Expect event to be instance of RTCPeerConnectionIceErrorEvent');
+ // Do not hardcode any specific errors here. Instead only verify
+ // that all the fields contain something expected.
+ // Testing of event.errorText can be added later once it's content is
+ // specified in spec with more detail.
+ assert_true(event.errorCode >= 300 && event.errorCode <= 799, "errorCode");
+ if (event.port == 0) {
+ assert_equals(event.address, null);
+ } else {
+ assert_true(event.address.includes(".") || event.address.includes(":"));
+ }
+ assert_true(event.url.includes("123"), "url");
+ });
+ const stream = await getNoiseStream({audio:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc.addTrack(stream.getAudioTracks()[0], stream);
+ await pc.setLocalDescription(await pc.createOffer());
+ await onErrorPromise;
+}, 'Surfacing onicecandidateerror');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>Test RTCPeerConnection.prototype.onnegotiationneeded</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateOffer
+ // generateAnswer
+ // generateAudioReceiveOnlyOffer
+ // test_never_resolve
+
+ // Listen to the negotiationneeded event on a peer connection
+ // Returns a promise that resolves when the first event is fired.
+ // The resolve result is a dictionary with event and nextPromise,
+ // which resolves when the next negotiationneeded event is fired.
+ // This allow us to promisify the event listening and assert whether
+ // an event is fired or not by testing whether a promise is resolved.
+ function awaitNegotiation(pc) {
+ if(pc.onnegotiationneeded) {
+ throw new Error('connection is already attached with onnegotiationneeded event handler');
+ }
+
+ function waitNextNegotiation() {
+ return new Promise(resolve => {
+ pc.onnegotiationneeded = event => {
+ const nextPromise = waitNextNegotiation();
+ resolve({ nextPromise, event });
+ }
+ });
+ }
+
+ return waitNextNegotiation();
+ }
+
+ // Return a promise that rejects if the first promise is resolved before second promise.
+ // Also rejects when either promise rejects.
+ function assert_first_promise_fulfill_after_second(promise1, promise2, message) {
+ if(!message) {
+ message = 'first promise is resolved before second promise';
+ }
+
+ return new Promise((resolve, reject) => {
+ let secondResolved = false;
+
+ promise1.then(() => {
+ if(secondResolved) {
+ resolve();
+ } else {
+ assert_unreached(message);
+ }
+ })
+ .catch(reject);
+
+ promise2.then(() => {
+ secondResolved = true;
+ }, reject);
+ });
+ }
+
+ /*
+ 4.7.3. Updating the Negotiation-Needed flag
+
+ To update the negotiation-needed flag
+ 5. Set connection's [[needNegotiation]] slot to true.
+ 6. Queue a task that runs the following steps:
+ 3. Fire a simple event named negotiationneeded at connection.
+
+ To check if negotiation is needed
+ 2. If connection has created any RTCDataChannels, and no m= section has
+ been negotiated yet for data, return "true".
+
+ 6.1. RTCPeerConnection Interface Extensions
+
+ createDataChannel
+ 14. If channel was the first RTCDataChannel created on connection,
+ update the negotiation-needed flag for connection.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const negotiated = awaitNegotiation(pc);
+
+ pc.createDataChannel('test');
+ return negotiated;
+ }, 'Creating first data channel should fire negotiationneeded event');
+
+ test_never_resolve(t => {
+ const pc = new RTCPeerConnection();
+ const negotiated = awaitNegotiation(pc);
+
+ pc.createDataChannel('foo');
+ return negotiated
+ .then(({nextPromise}) => {
+ pc.createDataChannel('bar');
+ return nextPromise;
+ });
+ }, 'calling createDataChannel twice should fire negotiationneeded event once');
+
+ /*
+ 4.7.3. Updating the Negotiation-Needed flag
+ To check if negotiation is needed
+ 3. For each transceiver t in connection's set of transceivers, perform
+ the following checks:
+ 1. If t isn't stopped and isn't yet associated with an m= section
+ according to [JSEP] (section 3.4.1.), return "true".
+
+ 5.1. RTCPeerConnection Interface Extensions
+ addTransceiver
+ 9. Update the negotiation-needed flag for connection.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const negotiated = awaitNegotiation(pc);
+
+ pc.addTransceiver('audio');
+ return negotiated;
+ }, 'addTransceiver() should fire negotiationneeded event');
+
+ /*
+ 4.7.3. Updating the Negotiation-Needed flag
+ To update the negotiation-needed flag
+ 4. If connection's [[needNegotiation]] slot is already true, abort these steps.
+ */
+ test_never_resolve(t => {
+ const pc = new RTCPeerConnection();
+ const negotiated = awaitNegotiation(pc);
+
+ pc.addTransceiver('audio');
+ return negotiated
+ .then(({nextPromise}) => {
+ pc.addTransceiver('video');
+ return nextPromise;
+ });
+ }, 'Calling addTransceiver() twice should fire negotiationneeded event once');
+
+ /*
+ 4.7.3. Updating the Negotiation-Needed flag
+ To update the negotiation-needed flag
+ 4. If connection's [[needNegotiation]] slot is already true, abort these steps.
+ */
+ test_never_resolve(t => {
+ const pc = new RTCPeerConnection();
+ const negotiated = awaitNegotiation(pc);
+
+ pc.createDataChannel('test');
+ return negotiated
+ .then(({nextPromise}) => {
+ pc.addTransceiver('video');
+ return nextPromise;
+ });
+ }, 'Calling both addTransceiver() and createDataChannel() should fire negotiationneeded event once');
+
+ /*
+ 4.7.3. Updating the Negotiation-Needed flag
+ To update the negotiation-needed flag
+ 2. If connection's signaling state is not "stable", abort these steps.
+ */
+ test_never_resolve(t => {
+ const pc = new RTCPeerConnection();
+ let negotiated;
+
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer => {
+ pc.setLocalDescription(offer);
+ negotiated = awaitNegotiation(pc);
+ })
+ .then(() => negotiated)
+ .then(({nextPromise}) => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ pc.createDataChannel('test');
+ return nextPromise;
+ });
+ }, 'negotiationneeded event should not fire if signaling state is not stable');
+
+ /*
+ 4.4.1.6. Set the RTCSessionSessionDescription
+ 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:
+ 2. If connection's [[NegotiationNeeded]] slot is false, abort these steps.
+ 3. Fire a simple event named negotiationneeded at connection.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio');
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ let fired = false;
+ pc.onnegotiationneeded = e => fired = true;
+ pc.createDataChannel('test');
+ await pc.setRemoteDescription(await generateAnswer(offer));
+ await undefined;
+ assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after SRD success");
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ }, 'negotiationneeded event should fire only after signaling state goes back to stable after setRemoteDescription');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio');
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+
+ let fired = false;
+ pc.onnegotiationneeded = e => fired = true;
+ await pc.setRemoteDescription(await generateOffer());
+ pc.createDataChannel('test');
+ await pc.setLocalDescription(await pc.createAnswer());
+ await undefined;
+ assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after SLD success");
+
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ }, 'negotiationneeded event should fire only after signaling state goes back to stable after setLocalDescription');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio');
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ let fired = false;
+ pc.onnegotiationneeded = e => fired = true;
+ pc.createDataChannel('test');
+ const p = pc.setRemoteDescription(await generateAnswer(offer));
+ await new Promise(resolve => pc.onsignalingstatechange = resolve);
+ assert_false(fired, "negotiationneeded should not fire before signalingstatechange fires");
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ await p;
+ }, 'negotiationneeded event should fire only after signalingstatechange event fires from setRemoteDescription');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio');
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+
+ let fired = false;
+ pc.onnegotiationneeded = e => fired = true;
+ await pc.setRemoteDescription(await generateOffer());
+ pc.createDataChannel('test');
+
+ const p = pc.setLocalDescription(await pc.createAnswer());
+ await new Promise(resolve => pc.onsignalingstatechange = resolve);
+ assert_false(fired, "negotiationneeded should not fire until the next iteration of the event loop after returning to stable");
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ await p;
+ }, 'negotiationneeded event should fire only after signalingstatechange event fires from setLocalDescription');
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+
+ addTrack
+ 10. Update the negotiation-needed flag for connection.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ pc.addTrack(track, stream);
+
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ }, 'addTrack should cause negotiationneeded to fire');
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+
+ removeTrack
+ 12. Update the negotiation-needed flag for connection.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ pc.onnegotiationneeded = t.step_func(() => {
+ assert_unreached('onnegotiationneeded misfired');
+ });
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+
+ pc.removeTrack(sender);
+ await new Promise(resolve => pc.onnegotiationneeded = resolve)
+ }, 'removeTrack should cause negotiationneeded to fire on the caller');
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+
+ removeTrack
+ 12. Update the negotiation-needed flag for connection.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ caller.addTransceiver('audio', {direction:'recvonly'});
+ const offer = await caller.createOffer();
+
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = callee.addTrack(track, stream);
+
+ await new Promise(resolve => callee.onnegotiationneeded = resolve);
+ callee.onnegotiationneeded = t.step_func(() => {
+ assert_unreached('onnegotiationneeded misfired');
+ });
+
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ callee.setLocalDescription(answer);
+
+ callee.removeTrack(sender);
+ await new Promise(resolve => callee.onnegotiationneeded = resolve)
+ }, 'removeTrack should cause negotiationneeded to fire on the callee');
+
+ /*
+ 5.4. RTCRtpTransceiver Interface
+
+ setDirection
+ 7. Update the negotiation-needed flag for connection.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio', {direction:'sendrecv'});
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+ transceiver.direction = 'recvonly';
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ }, 'Updating the direction of the transceiver should cause negotiationneeded to fire');
+
+ /*
+ 5.2. RTCRtpSender Interface
+
+ setStreams
+ 7. Update the negotiation-needed flag for connection.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver('audio', {direction:'sendrecv'});
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+
+ const stream = new MediaStream();
+ transceiver.sender.setStreams(stream);
+ await new Promise(resolve => pc.onnegotiationneeded = resolve);
+ }, 'Calling setStreams should cause negotiationneeded to fire');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ let negotiationCount = 0;
+ pc1.onnegotiationneeded = async () => {
+ negotiationCount++;
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+ }
+
+ pc1.addTransceiver("video");
+ await new Promise(r => pc1.onsignalingstatechange = () => pc1.signalingState == "stable" && r());
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onsignalingstatechange = () => pc1.signalingState == "stable" && r());
+ assert_equals(negotiationCount, 2);
+ }, 'Adding two transceivers, one at a time, results in the expected number of negotiationneeded events');
+
+ /*
+ TODO
+ 4.7.3. Updating the Negotiation-Needed flag
+
+ To update the negotiation-needed flag
+ 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.
+ 6. Queue a task that runs the following steps:
+ 2. If connection's [[needNegotiation]] slot is false, abort these steps.
+
+ To check if negotiation is needed
+ 3. For each transceiver t in connection's set of transceivers, perform
+ the following checks:
+ 2. If t isn't stopped and is associated with an m= section according
+ to [JSEP] (section 3.4.1.), then perform the following checks:
+ 1. If t's direction is "sendrecv" or "sendonly", and the
+ associated m= section in connection's currentLocalDescription
+ doesn't contain an "a=msid" line, return "true".
+ 2. If connection's currentLocalDescription if of type "offer",
+ and the direction of the associated m= section in neither the
+ offer nor answer matches t's direction, return "true".
+ 3. If connection's currentLocalDescription if of type "answer",
+ and the direction of the associated m= section in the answer
+ does not match t's direction intersected with the offered
+ direction (as described in [JSEP] (section 5.3.1.)),
+ return "true".
+ 3. If t is stopped and is associated with an m= section according
+ to [JSEP] (section 3.4.1.), but the associated m= section is
+ not yet rejected in connection's currentLocalDescription or
+ currentRemoteDescription , return "true".
+ 4. If all the preceding checks were performed and "true" was not returned,
+ nothing remains to be negotiated; return "false".
+
+ 4.3.1. RTCPeerConnection Operation
+
+ When the RTCPeerConnection() constructor is invoked
+ 7. Let connection have a [[needNegotiation]] internal slot, initialized to false.
+
+ 5.4. RTCRtpTransceiver Interface
+
+ 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>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection onsignalingstatechanged</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+
+promise_test(async t => {
+ const [track] = (await getNoiseStream({video: true})).getTracks();
+ t.add_cleanup(() => track.stop());
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTrack(track, new MediaStream());
+ await pc1.setLocalDescription(await pc1.createOffer());
+ const events = [];
+ pc2.onsignalingstatechange = t.step_func(e => {
+ const [transceiver] = pc2.getTransceivers();
+ assert_equals(transceiver.currentDirection, null);
+ events.push(pc2.signalingState);
+ });
+ await pc2.setRemoteDescription(pc1.localDescription);
+ assert_equals(events.length, 1, "event fired");
+ assert_equals(events[0], "have-remote-offer");
+
+ pc2.onsignalingstatechange = t.step_func(e => {
+ const [transceiver] = pc2.getTransceivers();
+ assert_equals(transceiver.currentDirection, "recvonly");
+ events.push(pc2.signalingState);
+ });
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ assert_equals(events.length, 2, "event fired");
+ assert_equals(events[1], "stable");
+}, 'Negotiation methods fire signalingstatechange events');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+
+ stream.getTracks().forEach(track => pc1.addTrack(track, stream));
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await listenToIceConnected(pc2);
+
+ pc2.onsignalingstatechange = t.unreached_func();
+ pc2.close();
+ assert_equals(pc2.signalingState, 'closed');
+ await new Promise(r => t.step_timeout(r, 100));
+}, 'Closing a PeerConnection should not fire signalingstatechange event');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc2.addTransceiver('video');
+
+ pc1.ontrack = t.unreached_func();
+ pc1.onsignalingstatechange = t.step_func(e => {
+ pc1.ontrack = null;
+ });
+ await pc1.setRemoteDescription(await pc2.createOffer());
+}, 'signalingstatechange is the first event to fire');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.ontrack</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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.
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ // Fail the test if the ontrack event handler is not implemented
+ 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=sendonly
+a=rtpmap:111 opus/48000/2
+a=msid:stream1 track1
+a=ssrc:1001 cname:some
+`;
+
+ const trackEventPromise = addEventListenerPromise(t, pc, 'track');
+ await pc.setRemoteDescription({ type: 'offer', sdp });
+ const trackEvent = await trackEventPromise;
+ 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)');
+ }, 'setRemoteDescription should trigger ontrack event when the MSID of the stream is is parsed.');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ 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');
+
+ await pc.setRemoteDescription({ type: 'offer', sdp });
+ await new Promise(resolve => t.step_timeout(resolve, 100));
+ }, 'setRemoteDescription() with m= line of recvonly direction should not trigger track event');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ const [track, mediaStream] = await getTrackFromUserMedia('audio');
+ pc1.addTrack(track, mediaStream);
+ const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ const trackEvent = await trackEventPromise;
+
+ assert_equals(trackEvent.track.kind, 'audio',
+ 'Expect track.kind to be audio');
+
+ validateTrackEvent(trackEvent);
+ }, 'addTrack() should cause remote connection to fire ontrack when setRemoteDescription()');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('video');
+
+ const trackEventPromise = addEventListenerPromise(t, pc2, 'track');
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ const trackEvent = await trackEventPromise;
+ const { track } = trackEvent;
+
+ assert_equals(track.kind, 'video',
+ 'Expect track.kind to be video');
+
+ validateTrackEvent(trackEvent);
+ }, `addTransceiver('video') should cause remote connection to fire ontrack when setRemoteDescription()`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'inactive' });
+ pc2.ontrack = t.unreached_func('ontrack event should not fire for track with inactive direction');
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ await new Promise(resolve => t.step_timeout(resolve, 100));
+ }, `addTransceiver() with inactive direction should not cause remote connection to fire ontrack when setRemoteDescription()`);
+
+ ["audio", "video"].forEach(type => promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const checkNoUnexpectedTrack = ({track}) => {
+ assert_equals(track.kind, type, `ontrack event should not fire for ${track.kind}`);
+ };
+
+ pc2.ontrack = t.step_func(checkNoUnexpectedTrack);
+ pc1.ontrack = t.step_func(checkNoUnexpectedTrack);
+
+ await pc1.setLocalDescription(await pc1.createOffer(
+ { offerToReceiveVideo: true, offerToReceiveAudio: true }));
+
+ pc2.addTrack(...await getTrackFromUserMedia(type));
+
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ await new Promise(resolve => t.step_timeout(resolve, 100));
+ }, `Using offerToReceiveAudio and offerToReceiveVideo should only cause a ${type} track event to fire, if ${type} was the only type negotiated`));
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script>
+'use strict';
+
+// Helpers to test APIs "return a promise rejected with a newly created" error.
+// Strictly speaking this means already-rejected upon return.
+function promiseState(p) {
+ const t = {};
+ return Promise.race([p, t])
+ .then(v => (v === t)? "pending" : "fulfilled", () => "rejected");
+}
+
+// However, to allow promises to be used in implementations, this helper adds
+// some slack: returning a pending promise will pass, provided it is rejected
+// before the end of the current run of the event loop (i.e. on microtask queue
+// before next task).
+async function promiseStateFinal(p) {
+ for (let i = 0; i < 20; i++) {
+ await promiseState(p);
+ }
+ return promiseState(p);
+}
+
+[promiseState, promiseStateFinal].forEach(f => promise_test(async t => {
+ assert_equals(await f(Promise.resolve()), "fulfilled");
+ assert_equals(await f(Promise.reject()), "rejected");
+ assert_equals(await f(new Promise(() => {})), "pending");
+}, `${f.name} helper works`));
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {track} = new RTCPeerConnection().addTransceiver("audio").receiver;
+ assert_not_equals(track, null);
+ const p = pc.getStats(track);
+ const haveState = promiseStateFinal(p);
+ try {
+ await p;
+ assert_unreached("Control. Must not succeed");
+ } catch (e) {
+ assert_equals(e.name, "InvalidAccessError");
+ }
+ assert_equals(await haveState, "rejected", "promise rejected on same task");
+}, "pc.getStats must detect InvalidAccessError synchronously always");
+
+// Helper builds on above tests to check if operations queue is empty or not.
+//
+// Meaning of "empty": Because this helper uses the sloppy promiseStateFinal,
+// it may not detect operations on the chain unless they block the current run
+// of the event loop. In other words, it may not detect operations on the chain
+// that resolve on the emptying of the microtask queue at the end of this run of
+// the event loop.
+
+async function isOperationsChainEmpty(pc) {
+ let p, error;
+ const signalingState = pc.signalingState;
+ if (signalingState == "have-remote-offer") {
+ p = pc.createOffer();
+ } else {
+ p = pc.createAnswer();
+ }
+ const state = await promiseStateFinal(p);
+ try {
+ await p;
+ // This helper tries to avoid side-effects by always failing,
+ // but createAnswer above may succeed if chained after an SRD
+ // that changes the signaling state on us. Ignore that success.
+ if (signalingState == pc.signalingState) {
+ assert_unreached("Control. Must not succeed");
+ }
+ } catch (e) {
+ assert_equals(e.name, "InvalidStateError",
+ "isOperationsChainEmpty is working");
+ }
+ return state == "rejected";
+}
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const p = pc.createOffer();
+ assert_false(await isOperationsChainEmpty(pc), "Non-empty chain");
+ await p;
+}, "createOffer uses operations chain");
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ pc1.addTransceiver("video");
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ const candidates = [];
+ for (let c; (c = (await new Promise(r => pc1.onicecandidate = r)).candidate);) {
+ candidates.push(c);
+ }
+ pc2.addTransceiver("video");
+ let fired = false;
+ const p = new Promise(r => pc2.onnegotiationneeded = () => r(fired = true));
+ await Promise.all([
+ pc2.setRemoteDescription(offer),
+ ...candidates.map(candidate => pc2.addIceCandidate(candidate)),
+ pc2.setLocalDescription()
+ ]);
+ assert_false(fired, "Negotiationneeded mustn't have fired yet.");
+ await new Promise(r => t.step_timeout(r, 0));
+ assert_true(fired, "Negotiationneeded must have fired by now.");
+ await p;
+}, "Negotiationneeded only fires once operations chain is empty");
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const offer = await pc.createOffer();
+ pc.addTransceiver("video");
+ await new Promise(r => pc.onnegotiationneeded = r);
+ const p = (async () => {
+ await pc.setLocalDescription();
+ })();
+ await new Promise(r => t.step_timeout(r, 0));
+ await pc.setRemoteDescription(offer);
+ await p;
+}, "Operations queue not vulnerable to recursion by chained negotiationneeded");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.removeTrack</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateAnswer
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+ partial interface RTCPeerConnection {
+ ...
+ void removeTrack(RTCRtpSender sender);
+ RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ optional RTCRtpTransceiverInit init);
+ };
+ */
+
+ // Before calling removeTrack can be tested, one needs to add MediaStreamTracks to
+ // a peer connection. There are two ways for adding MediaStreamTrack: addTrack and
+ // addTransceiver. addTransceiver is a newer API while addTrack has been implemented
+ // in current browsers for some time. As a result some of the removeTrack tests have
+ // two versions so that removeTrack can be partially tested without addTransceiver
+ // and the transceiver APIs being implemented.
+
+ /*
+ 5.1. removeTrack
+ 3. If connection's [[isClosed]] slot is true, throw an InvalidStateError.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ pc.close();
+ assert_throws_dom('InvalidStateError', () => pc.removeTrack(sender));
+ }, 'addTransceiver - Calling removeTrack when connection is closed should throw InvalidStateError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ pc.close();
+ assert_throws_dom('InvalidStateError', () => pc.removeTrack(sender));
+ }, 'addTrack - Calling removeTrack when connection is closed should throw InvalidStateError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ const pc2 = new RTCPeerConnection();
+ pc2.close();
+ assert_throws_dom('InvalidStateError', () => pc2.removeTrack(sender));
+ }, 'addTransceiver - Calling removeTrack on different connection that is closed should throw InvalidStateError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ const pc2 = new RTCPeerConnection();
+ pc2.close();
+ assert_throws_dom('InvalidStateError', () => pc2.removeTrack(sender));
+ }, 'addTrack - Calling removeTrack on different connection that is closed should throw InvalidStateError');
+
+ /*
+ 5.1. removeTrack
+ 4. If sender was not created by connection, throw an InvalidAccessError.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ assert_throws_dom('InvalidAccessError', () => pc2.removeTrack(sender));
+ }, 'addTransceiver - Calling removeTrack on different connection should throw InvalidAccessError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ assert_throws_dom('InvalidAccessError', () => pc2.removeTrack(sender));
+ }, 'addTrack - Calling removeTrack on different connection should throw InvalidAccessError')
+
+ /*
+ 5.1. removeTrack
+ 7. Set sender.track to null.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_equals(transceiver.currentDirection, null);
+
+ pc.removeTrack(sender);
+ assert_equals(sender.track, null);
+ assert_equals(transceiver.direction, 'recvonly');
+ }, 'addTransceiver - Calling removeTrack with valid sender should set sender.track to null');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({ audio: true });
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ assert_equals(sender.track, track);
+
+ pc.removeTrack(sender);
+ assert_equals(sender.track, null);
+ }, 'addTrack - Calling removeTrack with valid sender should set sender.track to null');
+
+ /*
+ 5.1. removeTrack
+ 7. Set sender.track to null.
+ 10. If transceiver.currentDirection is sendrecv set transceiver.direction
+ to recvonly.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = caller.addTransceiver(track);
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_equals(transceiver.currentDirection, null);
+
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ callee.addTrack(track, stream);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'sendrecv');
+
+ caller.removeTrack(sender);
+ assert_equals(sender.track, null);
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, 'sendrecv',
+ 'Expect currentDirection to not change');
+ }, 'Calling removeTrack with currentDirection sendrecv should set direction to recvonly');
+
+ /*
+ 5.1. removeTrack
+ 7. Set sender.track to null.
+ 11. If transceiver.currentDirection is sendonly set transceiver.direction
+ to inactive.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track, { direction: 'sendonly' });
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'sendonly');
+ assert_equals(transceiver.currentDirection, null);
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'sendonly');
+
+ pc.removeTrack(sender);
+ assert_equals(sender.track, null);
+ assert_equals(transceiver.direction, 'inactive');
+ assert_equals(transceiver.currentDirection, 'sendonly',
+ 'Expect currentDirection to not change');
+ }, 'Calling removeTrack with currentDirection sendonly should set direction to inactive');
+
+ /*
+ 5.1. removeTrack
+ 7. Set sender.track to null.
+ 9. If transceiver.currentDirection is recvonly or inactive,
+ then abort these steps.
+ */
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = caller.addTransceiver(track, { direction: 'recvonly' });
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, null);
+
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ callee.addTrack(track, stream);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'recvonly');
+
+ caller.removeTrack(sender);
+ assert_equals(sender.track, null);
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, 'recvonly');
+ }, 'Calling removeTrack with currentDirection recvonly should not change direction');
+
+ /*
+ 5.1. removeTrack
+ 7. Set sender.track to null.
+ 9. If transceiver.currentDirection is recvonly or inactive,
+ then abort these steps.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const transceiver = pc.addTransceiver(track, { direction: 'inactive' });
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+ assert_equals(transceiver.direction, 'inactive');
+ assert_equals(transceiver.currentDirection, null);
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const answer = await generateAnswer(offer);
+ await pc.setRemoteDescription(answer);
+ assert_equals(transceiver.currentDirection, 'inactive');
+
+ pc.removeTrack(sender);
+ assert_equals(sender.track, null);
+ assert_equals(transceiver.direction, 'inactive');
+ assert_equals(transceiver.currentDirection, 'inactive');
+ }, 'Calling removeTrack with currentDirection inactive should not change direction');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ pc.getTransceivers()[0].stop();
+ pc.removeTrack(sender);
+ assert_equals(sender.track, track);
+ }, "Calling removeTrack on a stopped transceiver should be a no-op");
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = pc.addTrack(track, stream);
+
+ await sender.replaceTrack(null);
+ pc.removeTrack(sender);
+ assert_equals(sender.track, null);
+}, "Calling removeTrack on a null track should have no effect");
+
+
+ /*
+ TODO
+ 5.1. removeTrack
+ Stops sending media from sender. The RTCRtpSender will still appear
+ in getSenders. Doing so will cause future calls to createOffer to
+ mark the media description for the corresponding transceiver as
+ recvonly or inactive, as defined in [JSEP] (section 5.2.2.).
+
+ When the other peer stops sending a track in this manner, an ended
+ event is fired at the MediaStreamTrack object.
+
+ 6. If sender is not in senders (which indicates that it was removed
+ due to setting an RTCSessionDescription of type "rollback"),
+ then abort these steps.
+ 12. Update the negotiation-needed flag for connection.
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+"use strict";
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ pc1.restartIce();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+ // When the setRemoteDescription() promise above is resolved a task should be
+ // queued to fire the onnegotiationneeded event. Because of this, we should
+ // have time to hook up the event listener *after* awaiting the SRD promise.
+ await new Promise(r => pc1.onnegotiationneeded = r);
+}, "Negotiation needed when returning to stable does not fire too early");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+"use strict";
+
+function getLines(sdp, startsWith) {
+ const lines = sdp.split("\r\n").filter(l => l.startsWith(startsWith));
+ assert_true(lines.length > 0, `One or more ${startsWith} in sdp`);
+ return lines;
+}
+
+const getUfrags = ({sdp}) => getLines(sdp, "a=ice-ufrag:");
+const getPwds = ({sdp}) => getLines(sdp, "a=ice-pwd:");
+
+const negotiators = [
+ {
+ tag: "",
+ async setOffer(pc) {
+ await pc.setLocalDescription(await pc.createOffer());
+ },
+ async setAnswer(pc) {
+ await pc.setLocalDescription(await pc.createAnswer());
+ },
+ },
+ {
+ tag: " (perfect negotiation)",
+ async setOffer(pc) {
+ await pc.setLocalDescription();
+ },
+ async setAnswer(pc) {
+ await pc.setLocalDescription();
+ },
+ },
+];
+
+async function exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator) {
+ await negotiator.setOffer(pc1);
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await negotiator.setAnswer(pc2);
+ await pc1.setRemoteDescription(pc2.localDescription); // End on pc1. No race
+}
+
+async function exchangeOfferAnswerEndOnSecond(pc1, pc2, negotiator) {
+ await negotiator.setOffer(pc1);
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc1.setRemoteDescription(await pc2.createAnswer());
+ await pc2.setLocalDescription(pc1.remoteDescription); // End on pc2. No race
+}
+
+async function assertNoNegotiationNeeded(t, pc, state = "stable") {
+ assert_equals(pc.signalingState, state, `In ${state} state`);
+ const event = await Promise.race([
+ new Promise(r => pc.onnegotiationneeded = r),
+ new Promise(r => t.step_timeout(r, 10))
+ ]);
+ assert_equals(event, undefined, "No negotiationneeded event");
+}
+
+// In Chromium, assert_equals() produces test expectations with the values
+// compared. Because ufrags are different on each run, this would make Chromium
+// test expectations different on each run on tests that failed when comparing
+// ufrags. To work around this problem, assert_ufrags_equals() and
+// assert_ufrags_not_equals() should be preferred over assert_equals() and
+// assert_not_equals().
+function assert_ufrags_equals(x, y, description) {
+ assert_true(x === y, description);
+}
+function assert_ufrags_not_equals(x, y, description) {
+ assert_false(x === y, description);
+}
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ pc.close();
+ pc.restartIce();
+ await assertNoNegotiationNeeded(t, pc, "closed");
+}, "restartIce() has no effect on a closed peer connection");
+
+// Run remaining tests twice: once for each negotiator
+
+for (const negotiator of negotiators) {
+ const {tag} = negotiator;
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ pc1.restartIce();
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() has no effect on initial negotiation${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ pc1.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ }, `restartIce() fires negotiationneeded after initial negotiation${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "control 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "control 2");
+
+ pc1.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
+ }, `restartIce() causes fresh ufrags${tag}`);
+
+ promise_test(async t => {
+ const config = {bundlePolicy: "max-bundle"};
+ const pc1 = new RTCPeerConnection(config);
+ const pc2 = new RTCPeerConnection(config);
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.onicecandidate = e => pc2.addIceCandidate(e.candidate);
+ pc2.onicecandidate = e => pc1.addIceCandidate(e.candidate);
+
+ // See the explanation below about Chrome's onnegotiationneeded firing
+ // too early.
+ const negotiationNeededPromise1 =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ pc1.addTransceiver("video");
+ pc1.addTransceiver("audio");
+ await negotiationNeededPromise1;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [videoTc, audioTc] = pc1.getTransceivers();
+ const [videoTp, audioTp] =
+ pc1.getTransceivers().map(tc => tc.sender.transport);
+ assert_equals(pc1.getTransceivers().length, 2, 'transceiver count');
+
+ // On Chrome, it is possible (likely, even) that videoTc.sender.transport.state
+ // will be 'connected' by the time we get here. We'll race 2 promises here:
+ // 1. Resolve after onstatechange is called with connected state.
+ // 2. If already connected, resolve immediately.
+ await Promise.race([
+ new Promise(r => videoTc.sender.transport.onstatechange =
+ () => videoTc.sender.transport.state == "connected" && r()),
+ new Promise(r => videoTc.sender.transport.state == "connected" && r())
+ ]);
+ assert_equals(videoTc.sender.transport.state, "connected");
+
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ assert_equals(videoTp, pc1.getTransceivers()[0].sender.transport,
+ 'offer/answer retains dtls transport');
+ assert_equals(audioTp, pc1.getTransceivers()[1].sender.transport,
+ 'offer/answer retains dtls transport');
+
+ const negotiationNeededPromise2 =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ pc1.restartIce();
+ await negotiationNeededPromise2;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [newVideoTp, newAudioTp] =
+ pc1.getTransceivers().map(tc => tc.sender.transport);
+ assert_equals(videoTp, newVideoTp, 'ice restart retains dtls transport');
+ assert_equals(audioTp, newAudioTp, 'ice restart retains dtls transport');
+ }, `restartIce() retains dtls transports${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ await negotiator.setOffer(pc1);
+ pc1.restartIce();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await negotiator.setAnswer(pc2);
+ // Several tests in this file initializes the onnegotiationneeded listener
+ // before the setLocalDescription() or setRemoteDescription() that we expect
+ // to trigger negotiation needed. This allows Chrome to exercise these tests
+ // without timing out due to a bug that causes onnegotiationneeded to fire too
+ // early.
+ // TODO(https://crbug.com/985797): Once Chrome does not fire ONN too early,
+ // simply do "await new Promise(...)" instead of
+ // "await negotiationNeededPromise" here and in other tests in this file.
+ const negotiationNeededPromise =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
+ await negotiationNeededPromise;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() works in have-local-offer${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await negotiator.setOffer(pc1);
+ pc1.restartIce();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await negotiator.setAnswer(pc2);
+ const negotiationNeededPromise =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+ await negotiationNeededPromise;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() works in initial have-local-offer${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ await negotiator.setOffer(pc2);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ pc1.restartIce();
+ await pc2.setRemoteDescription(await pc1.createAnswer());
+ const negotiationNeededPromise =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "Unchanged 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "Unchanged 2");
+ await negotiationNeededPromise;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() works in have-remote-offer${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc2.addTransceiver("audio");
+ await negotiator.setOffer(pc2);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ pc1.restartIce();
+ await pc2.setRemoteDescription(await pc1.createAnswer());
+ await pc1.setLocalDescription(pc2.remoteDescription); // End on pc1. No race
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() does nothing in initial have-remote-offer${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ pc1.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ const negotiationNeededPromise =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnSecond(pc2, pc1, negotiator);
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], oldUfrag1, "nothing yet 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], oldUfrag2, "nothing yet 2");
+ await negotiationNeededPromise;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag2, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() survives remote offer${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ pc1.restartIce();
+ pc2.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnSecond(pc2, pc1, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ assert_ufrags_equals(getUfrags(pc1.localDescription)[0], newUfrag1, "Unchanged 1");
+ assert_ufrags_equals(getUfrags(pc2.localDescription)[0], newUfrag2, "Unchanged 2");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() is satisfied by remote ICE restart${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ pc1.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await pc1.setLocalDescription(await pc1.createOffer({iceRestart: false}));
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await negotiator.setAnswer(pc2);
+ await pc1.setRemoteDescription(pc2.localDescription);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() trumps {iceRestart: false}${tag}`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+
+ const [oldUfrag1] = getUfrags(pc1.localDescription);
+ const [oldUfrag2] = getUfrags(pc2.localDescription);
+
+ pc1.restartIce();
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ await negotiator.setOffer(pc1);
+ const negotiationNeededPromise =
+ new Promise(r => pc1.onnegotiationneeded = r);
+ await pc1.setLocalDescription({type: "rollback"});
+ await negotiationNeededPromise;
+ await exchangeOfferAnswerEndOnFirst(pc1, pc2, negotiator);
+ const [newUfrag1] = getUfrags(pc1.localDescription);
+ const [newUfrag2] = getUfrags(pc2.localDescription);
+ assert_ufrags_not_equals(newUfrag1, oldUfrag1, "ufrag 1 changed");
+ assert_ufrags_not_equals(newUfrag1, oldUfrag2, "ufrag 2 changed");
+ await assertNoNegotiationNeeded(t, pc1);
+ }, `restartIce() survives rollback${tag}`);
+
+}
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Set Session Description - Transceiver Tests</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateAnswer
+
+ /*
+ 4.3.2. Interface Definition
+
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setLocalDescription(
+ RTCSessionDescriptionInit description);
+
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+
+ 5.4. RTCRtpTransceiver Interface
+
+ interface RTCRtpTransceiver {
+ readonly attribute DOMString? mid;
+ [SameObject]
+ readonly attribute RTCRtpSender sender;
+ [SameObject]
+ readonly attribute RTCRtpReceiver receiver;
+ readonly attribute RTCRtpTransceiverDirection direction;
+ readonly attribute RTCRtpTransceiverDirection? currentDirection;
+ ...
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 7. If description is set as a local description, then run the following steps for
+ each media description in description that is not yet associated with an
+ RTCRtpTransceiver object:
+ 1. Let transceiver be the RTCRtpTransceiver used to create the media
+ description.
+ 2. Set transceiver's mid value to the mid of the corresponding media
+ description.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.mid, null);
+
+ return pc.createOffer()
+ .then(offer => {
+ assert_equals(transceiver.mid, null,
+ 'Expect transceiver.mid to still be null after createOffer');
+
+ return pc.setLocalDescription(offer)
+ .then(() => {
+ assert_equals(typeof transceiver.mid, 'string',
+ 'Expect transceiver.mid to set to valid string value');
+
+ assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver.mid}`), true,
+ 'Expect transceiver mid to be found in offer SDP');
+ });
+ });
+ }, 'setLocalDescription(offer) with m= section should assign mid to corresponding transceiver');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 8. If description is set as a remote description, then run the following steps
+ for each media description in description:
+ 2. If no suitable transceiver is found (transceiver is unset), run the following
+ steps:
+ 1. Create an RTCRtpSender, sender, from the media description.
+ 2. Create an RTCRtpReceiver, receiver, from the media description.
+ 3. Create an RTCRtpTransceiver with sender, receiver and direction, and let
+ transceiver be the result.
+ 3. Set transceiver's mid value to the mid of the corresponding media description.
+ */
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ const transceiver1 = pc1.addTransceiver('audio');
+ assert_array_equals(pc1.getTransceivers(), [transceiver1]);
+ assert_array_equals(pc2.getTransceivers(), []);
+
+ return pc1.createOffer()
+ .then(offer => {
+ return Promise.all([
+ pc1.setLocalDescription(offer),
+ pc2.setRemoteDescription(offer)
+ ])
+ .then(() => {
+ const transceivers = pc2.getTransceivers();
+ assert_equals(transceivers.length, 1,
+ 'Expect new transceiver added to pc2 after setRemoteDescription');
+
+ const [ transceiver2 ] = transceivers;
+
+ assert_equals(typeof transceiver2.mid, 'string',
+ 'Expect transceiver2.mid to be set');
+
+ assert_equals(transceiver1.mid, transceiver2.mid,
+ 'Expect transceivers of both side to have the same mid');
+
+ assert_equals(offer.sdp.includes(`\r\na=mid:${transceiver2.mid}`), true,
+ 'Expect transceiver mid to be found in offer SDP');
+ });
+ });
+ }, 'setRemoteDescription(offer) with m= section and no existing transceiver should create corresponding transceiver');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 9. If description is of type "rollback", then run the following steps:
+ 1. If the mid value of an RTCRtpTransceiver was set to a non-null value by
+ the RTCSessionDescription that is being rolled back, set the mid value
+ of that transceiver to null, as described by [JSEP] (section 4.1.8.2.).
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.mid, null);
+
+ return pc.createOffer()
+ .then(offer => {
+ assert_equals(transceiver.mid, null);
+ return pc.setLocalDescription(offer);
+ })
+ .then(() => {
+ assert_not_equals(transceiver.mid, null);
+ return pc.setLocalDescription({ type: 'rollback' });
+ })
+ .then(() => {
+ assert_equals(transceiver.mid, null,
+ 'Expect transceiver.mid to become null again after rollback');
+ });
+ }, 'setLocalDescription(rollback) should unset transceiver.mid');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver1 = pc.addTransceiver('audio');
+ assert_equals(transceiver1.mid, null);
+
+ return pc.createOffer()
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer)))
+ .then(answer => pc.setRemoteDescription(answer))
+ .then(() => {
+ // pc is back to stable state
+ // create another transceiver
+ const transceiver2 = pc.addTransceiver('video');
+
+ assert_not_equals(transceiver1.mid, null);
+ assert_equals(transceiver2.mid, null);
+
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => {
+ assert_not_equals(transceiver1.mid, null);
+ assert_not_equals(transceiver2.mid, null,
+ 'Expect transceiver2.mid to become set');
+
+ return pc.setLocalDescription({ type: 'rollback' });
+ })
+ .then(() => {
+ assert_not_equals(transceiver1.mid, null,
+ 'Expect transceiver1.mid to stay set');
+
+ assert_equals(transceiver2.mid, null,
+ 'Expect transceiver2.mid to be rolled back to null');
+ });
+ })
+ }, 'setLocalDescription(rollback) should only unset transceiver mids associated with current round');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 9. If description is of type "rollback", then run the following steps:
+ 2. If an RTCRtpTransceiver was created by applying the RTCSessionDescription
+ that is being rolled back, and a track has not been attached to it via
+ addTrack, remove that transceiver from connection's set of transceivers,
+ as described by [JSEP] (section 4.1.8.2.).
+ */
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio');
+
+ return pc1.createOffer()
+ .then(offer => pc2.setRemoteDescription(offer))
+ .then(() => {
+ const transceivers = pc2.getTransceivers();
+ assert_equals(transceivers.length, 1);
+ const [ transceiver ] = transceivers;
+
+ assert_equals(typeof transceiver.mid, 'string',
+ 'Expect transceiver.mid to be set');
+
+ return pc2.setRemoteDescription({ type: 'rollback' })
+ .then(() => {
+ assert_equals(transceiver.mid, null,
+ 'Expect transceiver.mid to be unset');
+
+ assert_array_equals(pc2.getTransceivers(), [],
+ `Expect transceiver to be removed from pc2's transceiver list`);
+ });
+ });
+ }, 'setRemoteDescription(rollback) should remove newly created transceiver from transceiver list');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio');
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+
+ await pc2.setRemoteDescription(offer);
+ pc2.getTransceivers()[0].stop();
+ const answer = await pc2.createAnswer();
+
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(pc1.getTransceivers()[0].currentDirection, 'inactive', 'A stopped m-line should give an inactive transceiver');
+ }, 'setRemoteDescription should set transceiver inactive if its corresponding m section is rejected');
+
+ /*
+ TODO
+ - Steps for transceiver direction is added to tip of tree draft, but not yet
+ published as editor's draft
+
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 8. If description is set as a remote description, then run the following steps
+ for each media description in description:
+ 1. As described by [JSEP] (section 5.9.), attempt to find an existing
+ RTCRtpTransceiver object, transceiver, to represent the media description.
+ 3. 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. If the media description is rejected, and transceiver is not already stopped,
+ stop the RTCRtpTransceiver transceiver.
+
+ [JSEP]
+ 5.9. Applying a Remote Description
+ - If the m= section is not associated with any RtpTransceiver
+ (possibly because it was dissociated in the previous step),
+ either find an RtpTransceiver or create one according to the
+ following steps:
+
+ - If the m= section is sendrecv or recvonly, and there are
+ RtpTransceivers of the same type that were added to the
+ PeerConnection by addTrack and are not associated with any
+ m= section and are not stopped, find the first (according to
+ the canonical order described in Section 5.2.1) such
+ RtpTransceiver.
+
+ - If no RtpTransceiver was found in the previous step, create
+ one with a recvonly direction.
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setLocalDescription</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateAnswer
+ // assert_session_desc_similar
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.2. If description is set as a local description, then run one of the following
+ steps:
+
+ - If description is of type "answer", then this completes an offer answer
+ negotiation.
+
+ Set connection's currentLocalDescription to description and
+ currentRemoteDescription to the value of pendingRemoteDescription.
+
+ Set both pendingRemoteDescription and pendingLocalDescription to null.
+
+ Finally set connection's signaling state to stable.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer())
+ .then(answer =>
+ pc.setLocalDescription(answer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+ assert_session_desc_similar(pc.localDescription, answer);
+ assert_session_desc_similar(pc.remoteDescription, offer);
+
+ assert_session_desc_similar(pc.currentLocalDescription, answer);
+ assert_session_desc_similar(pc.currentRemoteDescription, offer);
+
+ assert_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.pendingRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer', 'stable']);
+ })));
+ }, 'setLocalDescription() with valid answer should succeed');
+
+ /*
+ 4.3.2. setLocalDescription
+ 3. Let lastAnswer be the result returned by the last call to createAnswer.
+ 4. If description.sdp is null and description.type is answer, set description.sdp
+ to lastAnswer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer())
+ .then(answer =>
+ pc.setLocalDescription({ type: 'answer' })
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+ assert_session_desc_similar(pc.localDescription, answer);
+ assert_session_desc_similar(pc.remoteDescription, offer);
+
+ assert_session_desc_similar(pc.currentLocalDescription, answer);
+ assert_session_desc_similar(pc.currentRemoteDescription, offer);
+
+ assert_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.pendingRemoteDescription, null);
+ })));
+ }, 'setLocalDescription() with type answer and null sdp should use lastAnswer generated from createAnswer');
+
+ /*
+ 4.3.2. setLocalDescription
+ 3. Let lastAnswer be the result returned by the last call to createAnswer.
+ 7. If description.type is answer and description.sdp does not match lastAnswer,
+ reject the promise with a newly created InvalidModificationError and abort these
+ steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => generateAnswer(offer))
+ .then(answer => pc.setLocalDescription(answer))
+ .then(() => t.unreached_func("setLocalDescription should have rejected"),
+ (error) => assert_equals(error.name, 'InvalidModificationError')));
+ }, 'setLocalDescription() with answer not created by own createAnswer() should reject with InvalidModificationError');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps.
+
+ [jsep]
+ 5.5. If the type is "pranswer" or "answer", the PeerConnection
+ state MUST be either "have-remote-offer" or "have-local-pranswer".
+ */
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer(); // [[LastAnswer]] slot set
+ await pc2.setRemoteDescription({type: "rollback"});
+ pc2.addTransceiver('video', { direction: 'recvonly' });
+ await pc2.createOffer(); // [[LastOffer]] slot set
+ await pc2.setRemoteDescription(offer);
+ await pc2.setLocalDescription(answer); // Should check against [[LastAnswer]], not [[LastOffer]]
+ }, "Setting previously generated answer after a call to createOffer should work");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ const answer = await pc2.createAnswer();
+ const sldPromise = pc2.setLocalDescription(answer);
+
+ assert_equals(pc2.signalingState, "have-remote-offer", "signalingState should not be set synchronously after a call to sLD");
+
+ assert_equals(pc2.pendingLocalDescription, null, "pendingLocalDescription should never be set due to sLD(answer)");
+ assert_not_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should not be set synchronously after a call to sLD");
+ assert_equals(pc2.pendingRemoteDescription.type, "offer");
+ assert_equals(pc2.remoteDescription.sdp, pc2.pendingRemoteDescription.sdp);
+ assert_equals(pc2.currentLocalDescription, null, "currentLocalDescription should not be set synchronously after a call to sLD");
+ assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sLD");
+
+ const stablePromise = new Promise(resolve => {
+ pc2.onsignalingstatechange = () => {
+ resolve(pc2.signalingState);
+ }
+ });
+ const raceValue = await Promise.race([stablePromise, sldPromise]);
+ assert_equals(raceValue, "stable", "signalingstatechange event should fire before sLD resolves");
+ assert_equals(pc2.pendingLocalDescription, null, "pendingLocalDescription should never be set due to sLD(answer)");
+ assert_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should be updated before the signalingstatechange event");
+ assert_not_equals(pc2.currentLocalDescription, null, "currentLocalDescription should be updated before the signalingstatechange event");
+ assert_equals(pc2.currentLocalDescription.type, "answer");
+ assert_equals(pc2.currentLocalDescription.sdp, pc2.localDescription.sdp);
+ assert_not_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should be updated before the signalingstatechange event");
+ assert_equals(pc2.currentRemoteDescription.type, "offer");
+ assert_equals(pc2.currentRemoteDescription.sdp, pc2.remoteDescription.sdp);
+
+ await sldPromise;
+ }, "setLocalDescription(answer) should update internal state with a queued task, in the right order");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setLocalDescription</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateDataChannelOffer
+ // assert_session_desc_not_similar
+ // assert_session_desc_similar
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.2. setLocalDescription
+ 2. Let lastOffer be the result returned by the last call to createOffer.
+ 5. If description.sdp is null and description.type is offer, set description.sdp
+ to lastOffer.
+
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.2. If description is set as a local description, then run one of the following
+ steps:
+ - If description is of type "offer", set connection.pendingLocalDescription
+ to description and signaling state to have-local-offer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer);
+ assert_equals(pc.currentLocalDescription, null);
+
+ assert_array_equals(states, ['have-local-offer']);
+ }));
+ }, 'setLocalDescription with valid offer should succeed');
+
+ /*
+ 4.3.2. setLocalDescription
+ 2. Let lastOffer be the result returned by the last call to createOffer.
+ 5. If description.sdp is null and description.type is offer, set description.sdp
+ to lastOffer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription({ type: 'offer' })
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer);
+ assert_equals(pc.currentLocalDescription, null);
+ }));
+ }, 'setLocalDescription with type offer and null sdp should use lastOffer generated from createOffer');
+
+ /*
+ 4.3.2. setLocalDescription
+ 2. Let lastOffer be the result returned by the last call to createOffer.
+ 6. If description.type is offer and description.sdp does not match lastOffer,
+ reject the promise with a newly created InvalidModificationError and abort
+ these steps.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ return generateDataChannelOffer(pc)
+ .then(offer => pc2.setLocalDescription(offer))
+ .then(() => t.unreached_func("setLocalDescription should have rejected"),
+ (error) => assert_equals(error.name, 'InvalidModificationError'));
+ }, 'setLocalDescription() with offer not created by own createOffer() should reject with InvalidModificationError');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer1 =>
+ pc.setLocalDescription(offer1)
+ .then(() =>
+ generateVideoReceiveOnlyOffer(pc)
+ .then(offer2 =>
+ pc.setLocalDescription(offer2)
+ .then(() => {
+ assert_session_desc_not_similar(offer1, offer2);
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_session_desc_similar(pc.localDescription, offer2);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer2);
+ assert_equals(pc.currentLocalDescription, null);
+
+ assert_array_equals(states, ['have-local-offer']);
+ }))));
+ }, 'Creating and setting offer multiple times should succeed');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const offer = await pc1.createOffer(); // [[LastOffer]] set
+ pc2.addTransceiver('video', { direction: 'recvonly' });
+ const offer2 = await pc2.createOffer();
+ await pc1.setRemoteDescription(offer2);
+ await pc1.createAnswer(); // [[LastAnswer]] set
+ await pc1.setRemoteDescription({type: "rollback"});
+ await pc1.setLocalDescription(offer);
+ }, "Setting previously generated offer after a call to createAnswer should work");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ await pc1.setLocalDescription(await pc1.createOffer());
+
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(pc1.getTransceivers().length, 1);
+ assert_equals(pc1.getTransceivers()[0].receiver.track.kind, "audio");
+ assert_equals(pc2.getTransceivers().length, 1);
+ assert_equals(pc2.getTransceivers()[0].receiver.track.kind, "audio");
+ }, "Negotiation works when there has been a repeated setLocalDescription(offer)");
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio', { direction: 'recvonly' });
+ const sldPromise = pc.setLocalDescription(await pc.createOffer());
+
+ assert_equals(pc.signalingState, "stable", "signalingState should not be set synchronously after a call to sLD");
+
+ assert_equals(pc.pendingLocalDescription, null, "pendingRemoteDescription should never be set due to sLD");
+ assert_equals(pc.pendingRemoteDescription, null, "pendingLocalDescription should not be set synchronously after a call to sLD");
+ assert_equals(pc.currentLocalDescription, null, "currentLocalDescription should not be set synchronously after a call to sLD");
+ assert_equals(pc.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sLD");
+
+ const statePromise = new Promise(resolve => {
+ pc.onsignalingstatechange = () => {
+ resolve(pc.signalingState);
+ }
+ });
+ const raceValue = await Promise.race([statePromise, sldPromise]);
+ assert_equals(raceValue, "have-local-offer", "signalingstatechange event should fire before sLD resolves");
+ assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD");
+ assert_not_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should be updated before the signalingstatechange event");
+ assert_equals(pc.pendingLocalDescription.type, "offer");
+ assert_equals(pc.pendingLocalDescription.sdp, pc.localDescription.sdp);
+ assert_equals(pc.currentLocalDescription, null, "currentLocalDescription should never be updated due to sLD(offer)");
+ assert_equals(pc.currentRemoteDescription, null, "currentRemoteDescription should never be updated due to sLD(offer)");
+
+ await sldPromise;
+ }, "setLocalDescription(offer) should update internal state with a queued task, in the right order");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+"use strict";
+
+const kSmallTimeoutMs = 100;
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+
+ const signalingStateChangeEvent
+ = new EventWatcher(t, offerer, 'signalingstatechange')
+ .wait_for('signalingstatechange');
+ await offerer.setLocalDescription();
+ await signalingStateChangeEvent;
+ assert_equals(offerer.signalingState, 'have-local-offer');
+}, "Parameterless SLD() in 'stable' goes to 'have-local-offer'");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+
+ await offerer.setLocalDescription();
+ assert_not_equals(offerer.pendingLocalDescription, null);
+}, "Parameterless SLD() in 'stable' sets pendingLocalDescription");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+
+ const transceiver = offerer.addTransceiver('audio');
+ assert_equals(transceiver.mid, null);
+ await offerer.setLocalDescription();
+ assert_not_equals(transceiver.mid, null);
+}, "Parameterless SLD() in 'stable' assigns transceiver.mid");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+ const answerer = new RTCPeerConnection();
+ t.add_cleanup(() => answerer.close());
+
+ await answerer.setRemoteDescription(await offerer.createOffer());
+ const signalingStateChangeEvent
+ = new EventWatcher(t, answerer, 'signalingstatechange')
+ .wait_for('signalingstatechange');
+ await answerer.setLocalDescription();
+ await signalingStateChangeEvent;
+ assert_equals(answerer.signalingState, 'stable');
+}, "Parameterless SLD() in 'have-remote-offer' goes to 'stable'");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+ const answerer = new RTCPeerConnection();
+ t.add_cleanup(() => answerer.close());
+
+ await answerer.setRemoteDescription(await offerer.createOffer());
+ await answerer.setLocalDescription();
+ assert_not_equals(answerer.currentLocalDescription, null);
+}, "Parameterless SLD() in 'have-remote-offer' sets currentLocalDescription");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+ const answerer = new RTCPeerConnection();
+ t.add_cleanup(() => answerer.close());
+
+ offerer.addTransceiver('audio');
+ const onTransceiverPromise = new Promise(resolve =>
+ answerer.ontrack = e => resolve(e.transceiver));
+ await answerer.setRemoteDescription(await offerer.createOffer());
+ const transceiver = await onTransceiverPromise;
+ await answerer.setLocalDescription();
+ assert_equals(transceiver.currentDirection, 'recvonly');
+}, "Parameterless SLD() in 'have-remote-offer' sets " +
+ "transceiver.currentDirection");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ offerer.close();
+ try {
+ await offerer.setLocalDescription();
+ assert_not_reached();
+ } catch (e) {
+ assert_equals(e.name, "InvalidStateError");
+ }
+}, "Parameterless SLD() rejects with InvalidStateError if already closed");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+
+ const p = Promise.race([
+ offerer.setLocalDescription(),
+ new Promise(r => t.step_timeout(() => r("timeout"), kSmallTimeoutMs))
+ ]);
+ offerer.close();
+ assert_equals(await p, "timeout");
+}, "Parameterless SLD() never settles if closed while pending");
+
+promise_test(async t => {
+ const offerer = new RTCPeerConnection();
+ t.add_cleanup(() => offerer.close());
+ const answerer = new RTCPeerConnection();
+ t.add_cleanup(() => answerer.close());
+
+ // Implicitly create an offer.
+ await offerer.setLocalDescription();
+ await answerer.setRemoteDescription(offerer.pendingLocalDescription);
+ // Implicitly create an answer.
+ await answerer.setLocalDescription();
+ await offerer.setRemoteDescription(answerer.currentLocalDescription);
+}, "Parameterless SLD() in a full O/A exchange succeeds");
+
+promise_test(async t => {
+ const answerer = new RTCPeerConnection();
+ try {
+ await answerer.setRemoteDescription();
+ assert_not_reached();
+ } catch (e) {
+ assert_equals(e.name, "TypeError");
+ }
+}, "Parameterless SRD() rejects with TypeError.");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setLocalDescription pranswer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // assert_session_desc_similar
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setLocalDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? localDescription;
+ readonly attribute RTCSessionDescription? currentLocalDescription;
+ readonly attribute RTCSessionDescription? pendingLocalDescription;
+
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps.
+
+ [jsep]
+ 5.5. If the type is "pranswer" or "answer", the PeerConnection
+ state MUST be either "have-remote-offer" or "have-local-pranswer".
+ */
+
+ /*
+ 4.3.1.6 Set the RTCSessionSessionDescription
+ 2.2.2. If description is set as a local description, then run one of the
+ following steps:
+ - If description is of type "pranswer", then set
+ connection.pendingLocalDescription to description and signaling state to
+ have-local-pranswer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer())
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setLocalDescription(pranswer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-pranswer');
+
+ assert_session_desc_similar(pc.remoteDescription, offer);
+ assert_session_desc_similar(pc.pendingRemoteDescription, offer);
+ assert_equals(pc.currentRemoteDescription, null);
+
+ assert_session_desc_similar(pc.localDescription, pranswer);
+ assert_session_desc_similar(pc.pendingLocalDescription, pranswer);
+ assert_equals(pc.currentLocalDescription, null);
+
+
+ assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer']);
+ });
+ }));
+ }, 'setLocalDescription(pranswer) should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer())
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setLocalDescription(pranswer)
+ .then(() => pc.setLocalDescription(pranswer))
+ .then(() => {
+ assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer']);
+ });
+ }));
+ }, 'setLocalDescription(pranswer) can be applied multiple times while still in have-local-pranswer');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer())
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setLocalDescription(pranswer)
+ .then(() => pc.setLocalDescription(answer))
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+ assert_session_desc_similar(pc.localDescription, answer);
+ assert_session_desc_similar(pc.remoteDescription, offer);
+
+ assert_session_desc_similar(pc.currentLocalDescription, answer);
+ assert_session_desc_similar(pc.currentRemoteDescription, offer);
+
+ assert_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.pendingRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer', 'have-local-pranswer', 'stable']);
+ });
+ }));
+ }, 'setLocalDescription(answer) from have-local-pranswer state should succeed');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setLocalDescription rollback</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // assert_session_desc_similar
+ // generateAudioReceiveOnlyOffer
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setLocalDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? localDescription;
+ readonly attribute RTCSessionDescription? currentLocalDescription;
+ readonly attribute RTCSessionDescription? pendingLocalDescription;
+
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.2. If description is set as a local description, then run one of the
+ following steps:
+ - If description is of type "rollback", then this is a rollback. Set
+ connection.pendingLocalDescription to null and signaling state to stable.
+ */
+ promise_test(t=> {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_not_equals(pc.localDescription, null);
+ assert_not_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.currentLocalDescription, null);
+
+ return pc.setLocalDescription({ type: 'rollback' });
+ })
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+ assert_equals(pc.localDescription, null);
+ assert_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.currentLocalDescription, null);
+
+ assert_array_equals(states, ['have-local-offer', 'stable']);
+ });
+ }, 'setLocalDescription(rollback) from have-local-offer state should reset back to stable state');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps. Note that this implies that once the answerer has performed
+ setLocalDescription with his answer, this cannot be rolled back.
+
+ [jsep]
+ 4.1.8.2. Rollback
+ - Rollback can only be used to cancel proposed changes;
+ there is no support for rolling back from a stable state to a
+ previous stable state
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return promise_rejects_dom(t, 'InvalidStateError',
+ pc.setLocalDescription({ type: 'rollback' }));
+ }, `setLocalDescription(rollback) from stable state should reject with InvalidStateError`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => pc.createAnswer()))
+ .then(answer => pc.setLocalDescription(answer))
+ .then(() => {
+ return promise_rejects_dom(t, 'InvalidStateError',
+ pc.setLocalDescription({ type: 'rollback' }));
+ });
+ }, `setLocalDescription(rollback) after setting answer description should reject with InvalidStateError`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => pc.setLocalDescription({
+ type: 'rollback',
+ sdp: '!<Invalid SDP Content>;'
+ }));
+ }, `setLocalDescription(rollback) should ignore invalid sdp content and succeed`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio', { direction: 'recvonly' });
+ await pc.setLocalDescription(await pc.createOffer());
+ const sldPromise = pc.setLocalDescription({type: "rollback"});
+
+ assert_equals(pc.signalingState, "have-local-offer", "signalingState should not be set synchronously after a call to sLD");
+
+ assert_not_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should not be set synchronously after a call to sLD");
+ assert_equals(pc.pendingLocalDescription.type, "offer");
+ assert_equals(pc.pendingLocalDescription.sdp, pc.localDescription.sdp);
+ assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD(offer)");
+
+ const stablePromise = new Promise(resolve => {
+ pc.onsignalingstatechange = () => {
+ resolve(pc.signalingState);
+ }
+ });
+ const raceValue = await Promise.race([stablePromise, sldPromise]);
+ assert_equals(raceValue, "stable", "signalingstatechange event should fire before sLD resolves");
+ assert_equals(pc.pendingLocalDescription, null, "pendingLocalDescription should be updated before the signalingstatechange event");
+ assert_equals(pc.pendingRemoteDescription, null, "pendingRemoteDescription should never be set due to sLD(offer)");
+
+ await sldPromise;
+ }, "setLocalDescription(rollback) should update internal state with a queued tassk, in the right order");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setLocalDescription</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateDataChannelOffer
+ // assert_session_desc_not_similar
+ // assert_session_desc_similar
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer1 =>
+ pc.setLocalDescription(offer1)
+ .then(() => generateAnswer(offer1))
+ .then(answer => pc.setRemoteDescription(answer))
+ .then(() => {
+ pc.createDataChannel('test');
+ return generateVideoReceiveOnlyOffer(pc);
+ })
+ .then(offer2 =>
+ pc.setLocalDescription(offer2)
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-local-offer');
+ assert_session_desc_not_similar(offer1, offer2);
+ assert_session_desc_similar(pc.localDescription, offer2);
+ assert_session_desc_similar(pc.currentLocalDescription, offer1);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer2);
+
+ assert_array_equals(states, ['have-local-offer', 'stable', 'have-local-offer']);
+ })));
+ }, 'Calling createOffer() and setLocalDescription() again after one round of local-offer/remote-answer should succeed');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ pc1.addEventListener('signalingstatechange', () => states.push(pc1.signalingState));
+
+ assert_equals(pc1.localDescription, null);
+ assert_equals(pc1.currentLocalDescription, null);
+ assert_equals(pc1.pendingLocalDescription, null);
+
+ pc1.createDataChannel('test');
+ const offer = await pc1.createOffer();
+
+ assert_equals(pc1.localDescription, null);
+ assert_equals(pc1.currentLocalDescription, null);
+ assert_equals(pc1.pendingLocalDescription, null);
+
+ await pc1.setLocalDescription(offer);
+
+ assert_session_desc_similar(pc1.localDescription, offer);
+ assert_equals(pc1.currentLocalDescription, null);
+ assert_session_desc_similar(pc1.pendingLocalDescription, offer);
+
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(pc1.signalingState, 'stable');
+ assert_session_desc_similar(pc1.localDescription, offer);
+ assert_session_desc_similar(pc1.currentLocalDescription, offer);
+ assert_equals(pc1.pendingLocalDescription, null);
+
+ const stream = await getNoiseStream({audio:true});
+ pc2.addTrack(stream.getTracks()[0], stream);
+
+ const reoffer = await pc2.createOffer();
+ await pc2.setLocalDescription(reoffer);
+ await pc1.setRemoteDescription(reoffer);
+ const reanswer = await pc1.createAnswer();
+ await pc1.setLocalDescription(reanswer);
+
+ assert_session_desc_similar(pc1.localDescription, reanswer);
+ assert_session_desc_similar(pc1.currentLocalDescription, reanswer);
+ assert_equals(pc1.pendingLocalDescription, null);
+ }, 'Switching role from answerer to offerer after going back to stable state should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const offer = await pc.createOffer();
+ let eventSequence = '';
+ const signalingstatechangeResolver = new Resolver();
+ pc.onsignalingstatechange = () => {
+ eventSequence += 'onsignalingstatechange;';
+ signalingstatechangeResolver.resolve();
+ };
+ await pc.setLocalDescription(offer);
+ eventSequence += 'setLocalDescription;';
+ await signalingstatechangeResolver;
+ assert_equals(eventSequence, 'onsignalingstatechange;setLocalDescription;');
+ }, 'onsignalingstatechange fires before setLocalDescription resolves');
+
+ /*
+ TODO
+ 4.3.2. setLocalDescription
+ 4. If description.sdp is null and description.type is pranswer, set description.sdp
+ to lastAnswer.
+ 7. If description.type is pranswer and description.sdp does not match lastAnswer,
+ reject the promise with a newly created InvalidModificationError and abort these
+ steps.
+ */
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription - answer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateAnswer()
+ // assert_session_desc_similar()
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.3. Otherwise, if description is set as a remote description, then run one of
+ the following steps:
+ - If description is of type "answer", then this completes an offer answer
+ negotiation.
+
+ Set connection's currentRemoteDescription to description and
+ currentLocalDescription to the value of pendingLocalDescription.
+
+ Set both pendingRemoteDescription and pendingLocalDescription to null.
+
+ Finally setconnection's signaling state to stable.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer))
+ .then(answer =>
+ pc.setRemoteDescription(answer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.remoteDescription, answer);
+
+ assert_session_desc_similar(pc.currentLocalDescription, offer);
+ assert_session_desc_similar(pc.currentRemoteDescription, answer);
+
+ assert_equals(pc.pendingLocalDescription, null);
+ assert_equals(pc.pendingRemoteDescription, null);
+
+ assert_array_equals(states, ['have-local-offer', 'stable']);
+ })));
+ }, 'setRemoteDescription() with valid state and answer should succeed');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.1.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps.
+
+ [JSEP]
+ 5.6. If the type is "answer", the PeerConnection state MUST be either
+ "have-local-offer" or "have-remote-pranswer".
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer()
+ .then(offer =>
+ promise_rejects_dom(t, 'InvalidStateError',
+ pc.setRemoteDescription({ type: 'answer', sdp: offer.sdp })));
+ }, 'Calling setRemoteDescription(answer) from stable state should reject with InvalidStateError');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer()
+ .then(offer =>
+ pc.setRemoteDescription(offer)
+ .then(() => generateAnswer(offer)))
+ .then(answer =>
+ promise_rejects_dom(t, 'InvalidStateError',
+ pc.setRemoteDescription(answer)));
+ }, 'Calling setRemoteDescription(answer) from have-remote-offer state should reject with InvalidStateError');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription - legacy streams without a=msid lines</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+const FINGERPRINT_SHA256 = '00:00:00:00:00:00:00:00:00:00:00:00:00' +
+ ':00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00';
+const ICEUFRAG = 'someufrag';
+const ICEPWD = 'somelongpwdwithenoughrandomness';
+const SDP_BOILERPLATE = 'v=0\r\n' +
+ 'o=- 166855176514521964 2 IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n';
+const MINIMAL_AUDIO_MLINE =
+ 'm=audio 9 UDP/TLS/RTP/SAVPF 111\r\n' +
+ 'c=IN IP4 0.0.0.0\r\n' +
+ 'a=rtcp:9 IN IP4 0.0.0.0\r\n' +
+ 'a=ice-ufrag:' + ICEUFRAG + '\r\n' +
+ 'a=ice-pwd:' + ICEPWD + '\r\n' +
+ 'a=fingerprint:sha-256 ' + FINGERPRINT_SHA256 + '\r\n' +
+ 'a=setup:actpass\r\n' +
+ 'a=mid:0\r\n' +
+ 'a=sendrecv\r\n' +
+ 'a=rtcp-mux\r\n' +
+ 'a=rtcp-rsize\r\n' +
+ 'a=rtpmap:111 opus/48000/2\r\n';
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const haveOntrack = new Promise(r => pc.ontrack = r);
+ await pc.setRemoteDescription({type: 'offer', sdp: SDP_BOILERPLATE + MINIMAL_AUDIO_MLINE});
+ assert_equals((await haveOntrack).streams.length, 1);
+ }, 'setRemoteDescription with an SDP without a=msid lines triggers ontrack with a default stream.');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription - offer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // assert_session_desc_similar()
+ // generateAudioReceiveOnlyOffer
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.3. Otherwise, if description is set as a remote description, then run one of
+ the following steps:
+ - If description is of type "offer", set connection.pendingRemoteDescription
+ attribute to description and signaling state to have-remote-offer.
+ */
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ pc1.createDataChannel('datachannel');
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
+
+ return pc1.createOffer()
+ .then(offer => {
+ return pc2.setRemoteDescription(offer)
+ .then(() => {
+ assert_equals(pc2.signalingState, 'have-remote-offer');
+ assert_session_desc_similar(pc2.remoteDescription, offer);
+ assert_session_desc_similar(pc2.pendingRemoteDescription, offer);
+ assert_equals(pc2.currentRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer']);
+ });
+ });
+ }, 'setRemoteDescription with valid offer should succeed');
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ pc1.createDataChannel('datachannel');
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
+
+ return pc1.createOffer()
+ .then(offer => {
+ return pc2.setRemoteDescription(offer)
+ .then(() => pc2.setRemoteDescription(offer))
+ .then(() => {
+ assert_equals(pc2.signalingState, 'have-remote-offer');
+ assert_session_desc_similar(pc2.remoteDescription, offer);
+ assert_session_desc_similar(pc2.pendingRemoteDescription, offer);
+ assert_equals(pc2.currentRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer']);
+ });
+ });
+ }, 'setRemoteDescription multiple times should succeed');
+
+ promise_test(t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ pc1.createDataChannel('datachannel');
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ pc2.addEventListener('signalingstatechange', () => states.push(pc2.signalingState));
+
+ return pc1.createOffer()
+ .then(offer1 => {
+ return pc1.setLocalDescription(offer1)
+ .then(()=> {
+ return generateAudioReceiveOnlyOffer(pc1)
+ .then(offer2 => {
+ assert_session_desc_not_similar(offer1, offer2);
+
+ return pc2.setRemoteDescription(offer1)
+ .then(() => pc2.setRemoteDescription(offer2))
+ .then(() => {
+ assert_equals(pc2.signalingState, 'have-remote-offer');
+ assert_session_desc_similar(pc2.remoteDescription, offer2);
+ assert_session_desc_similar(pc2.pendingRemoteDescription, offer2);
+ assert_equals(pc2.currentRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer']);
+ });
+ });
+ });
+ });
+ }, 'setRemoteDescription multiple times with different offer should succeed');
+
+ /*
+ 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
+ error was detected) and abort these steps.
+ */
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc1.setRemoteDescription(await pc2.createOffer());
+ assert_equals(pc1.signalingState, 'have-remote-offer');
+ }, 'setRemoteDescription(offer) from have-local-offer should roll back and succeed');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const srdPromise = pc2.setRemoteDescription(await pc1.createOffer());
+
+ assert_equals(pc2.signalingState, "stable", "signalingState should not be set synchronously after a call to sRD");
+
+ assert_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should not be set synchronously after a call to sRD");
+ assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set synchronously after a call to sRD");
+
+ const statePromise = new Promise(resolve => {
+ pc2.onsignalingstatechange = () => {
+ resolve(pc2.signalingState);
+ }
+ });
+
+ const raceValue = await Promise.race([statePromise, srdPromise]);
+ assert_equals(raceValue, "have-remote-offer", "signalingstatechange event should fire before sRD resolves");
+ assert_not_equals(pc2.pendingRemoteDescription, null, "pendingRemoteDescription should be updated before the signalingstatechange event");
+ assert_equals(pc2.pendingRemoteDescription.type, "offer");
+ assert_equals(pc2.pendingRemoteDescription.sdp, pc2.remoteDescription.sdp);
+ assert_equals(pc2.currentRemoteDescription, null, "currentRemoteDescription should not be set after a call to sRD(offer)");
+
+ await srdPromise;
+ }, "setRemoteDescription(offer) in stable should update internal state with a queued task, in the right order");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ await pc1.setLocalDescription(await pc1.createOffer());
+ const p = pc1.setRemoteDescription(await pc2.createOffer());
+ await new Promise(r => pc1.onsignalingstatechange = r);
+ assert_equals(pc1.signalingState, 'stable');
+ await pc1.addIceCandidate();
+ await p;
+ assert_equals(pc1.signalingState, 'have-remote-offer');
+ }, 'setRemoteDescription(offer) from have-local-offer is glare-proof');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('video');
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ assert_equals(pc2.getTransceivers().length, 1);
+ await pc2.setRemoteDescription(offer);
+ assert_equals(pc2.getTransceivers().length, 1);
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ }, 'repeated sRD(offer) works');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('video');
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForIceGatheringState(pc1, ['complete']);
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForIceStateChange(pc2, ['connected', 'completed']);
+ }, 'sRD(reoffer) with candidates and without trickle works');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('video');
+ const offer = await pc1.createOffer();
+ const srdPromise = pc2.setRemoteDescription(offer);
+ assert_equals(pc2.getTransceivers().length, 0);
+ await srdPromise;
+ assert_equals(pc2.getTransceivers().length, 1);
+ }, 'Transceivers added by sRD(offer) should not show up until sRD resolves');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription pranswer</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // generateAnswer
+ // assert_session_desc_similar
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setLocalDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? localDescription;
+ readonly attribute RTCSessionDescription? currentLocalDescription;
+ readonly attribute RTCSessionDescription? pendingLocalDescription;
+
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.1.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps.
+
+ [JSEP]
+ 5.6. If the type is "pranswer" or "answer", the PeerConnection state MUST be either
+ "have-local-offer" or "have-remote-pranswer".
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer()
+ .then(offer =>
+ promise_rejects_dom(t, 'InvalidStateError',
+ pc.setRemoteDescription({ type: 'pranswer', sdp: offer.sdp })));
+ }, 'setRemoteDescription(pranswer) from stable state should reject with InvalidStateError');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.3. Otherwise, if description is set as a remote description, then run one
+ of the following steps:
+ - If description is of type "pranswer", then set
+ connection.pendingRemoteDescription to description and signaling state
+ to have-remote-pranswer.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer))
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setRemoteDescription(pranswer)
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-remote-pranswer');
+
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.pendingLocalDescription, offer);
+ assert_equals(pc.currentLocalDescription, null);
+
+ assert_session_desc_similar(pc.remoteDescription, pranswer);
+ assert_session_desc_similar(pc.pendingRemoteDescription, pranswer);
+ assert_equals(pc.currentRemoteDescription, null);
+
+ assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer']);
+ });
+ }));
+ }, 'setRemoteDescription(pranswer) from have-local-offer state should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer))
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setRemoteDescription(pranswer)
+ .then(() => pc.setRemoteDescription(pranswer))
+ .then(() => {
+ assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer']);
+ });
+ }));
+ }, 'setRemoteDescription(pranswer) multiple times should succeed');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateVideoReceiveOnlyOffer(pc)
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer))
+ .then(answer => {
+ const pranswer = { type: 'pranswer', sdp: answer.sdp };
+
+ return pc.setRemoteDescription(pranswer)
+ .then(() => pc.setRemoteDescription(answer))
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+
+ assert_session_desc_similar(pc.localDescription, offer);
+ assert_session_desc_similar(pc.currentLocalDescription, offer);
+ assert_equals(pc.pendingLocalDescription, null);
+
+ assert_session_desc_similar(pc.remoteDescription, answer);
+ assert_session_desc_similar(pc.currentRemoteDescription, answer);
+ assert_equals(pc.pendingRemoteDescription, null);
+
+ assert_array_equals(states, ['have-local-offer', 'have-remote-pranswer', 'stable']);
+ });
+ }));
+ }, 'setRemoteDescription(answer) from have-remote-pranswer state should succeed');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription - replaceTrack</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // getUserMediaTracksAndStreams
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ return sender.replaceTrack(tracks[1])
+ .then(t.step_func(() => {
+ assert_equals(sender.track, tracks[1]);
+ t.done();
+ }));
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() sets the track attribute to a new track.');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ return sender.replaceTrack(null)
+ .then(t.step_func(() => {
+ assert_equals(sender.track, null);
+ t.done();
+ }));
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() sets the track attribute to null.');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ assert_equals(sender.track, tracks[0]);
+ sender.replaceTrack(tracks[1]);
+ // replaceTrack() is asynchronous, there should be no synchronously
+ // observable effects.
+ assert_equals(sender.track, tracks[0]);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() does not set the track synchronously.');
+
+ async_test(t => {
+ const expectedException = 'InvalidStateError';
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ caller.close();
+ return sender.replaceTrack(tracks[1])
+ .then(t.step_func(() => {
+ assert_unreached('Expected replaceTrack() to be rejected with ' +
+ expectedException + ' but the promise was resolved.');
+ }),
+ t.step_func(e => {
+ assert_equals(e.name, expectedException);
+ t.done();
+ }));
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() rejects when the peer connection is closed.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ caller.removeTrack(sender);
+ await sender.replaceTrack(tracks[1]);
+ assert_equals(sender.track, tracks[1], "Make sure track gets updated");
+ }, 'replaceTrack() does not reject when invoked after removeTrack().');
+
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ const sender = caller.addTrack(tracks[0], streams[0]);
+ let p = sender.replaceTrack(tracks[1])
+ caller.removeTrack(sender);
+ await p;
+ assert_equals(sender.track, tracks[1], "Make sure track gets updated");
+ }, 'replaceTrack() does not reject after a subsequent removeTrack().');
+
+ // TODO(hbos): Verify that replaceTrack() changes what media is received on
+ // the remote end of two connected peer connections. For video tracks, this
+ // requires Chromium's video tag to update on receiving frames when running
+ // content_shell. https://crbug.com/793808
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription rollback</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // assert_session_desc_similar
+ // generateAudioReceiveOnlyOffer
+ // generateDataChannelOffer
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setLocalDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? localDescription;
+ readonly attribute RTCSessionDescription? currentLocalDescription;
+ readonly attribute RTCSessionDescription? pendingLocalDescription;
+
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.2.3. Otherwise, if description is set as a remote description, then run one
+ of the following steps:
+ - If description is of type "rollback", then this is a rollback.
+ Set connection.pendingRemoteDescription to null and signaling state to stable.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const states = [];
+ pc.addEventListener('signalingstatechange', () => states.push(pc.signalingState));
+
+ return generateDataChannelOffer(pc)
+ .then(offer => pc.setRemoteDescription(offer))
+ .then(() => {
+ assert_equals(pc.signalingState, 'have-remote-offer');
+ assert_not_equals(pc.remoteDescription, null);
+ assert_not_equals(pc.pendingRemoteDescription, null);
+ assert_equals(pc.currentRemoteDescription, null);
+
+ return pc.setRemoteDescription({type: 'rollback'});
+ })
+ .then(() => {
+ assert_equals(pc.signalingState, 'stable');
+ assert_equals(pc.remoteDescription, null);
+ assert_equals(pc.pendingRemoteDescription, null);
+ assert_equals(pc.currentRemoteDescription, null);
+
+ assert_array_equals(states, ['have-remote-offer', 'stable']);
+ });
+ }, 'setRemoteDescription(rollback) in have-remote-offer state should revert to stable state');
+
+ /*
+ 4.3.1.6. Set the RTCSessionSessionDescription
+ 2.3. If the description's type is invalid for the current signaling state of
+ connection, then reject p with a newly created InvalidStateError and abort
+ these steps.
+
+ [jsep]
+ 4.1.8.2. Rollback
+ - Rollback can only be used to cancel proposed changes;
+ there is no support for rolling back from a stable state to a
+ previous stable state
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return promise_rejects_dom(t, 'InvalidStateError',
+ pc.setRemoteDescription({type: 'rollback'}));
+ }, `setRemoteDescription(rollback) from stable state should reject with InvalidStateError`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return generateAudioReceiveOnlyOffer(pc)
+ .then(offer => pc.setRemoteDescription(offer))
+ .then(() => pc.setRemoteDescription({
+ type: 'rollback',
+ sdp: '!<Invalid SDP Content>;'
+ }));
+ }, `setRemoteDescription(rollback) should ignore invalid sdp content and succeed`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ // We don't use this right away
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const offer1 = await pc1.createOffer();
+
+ // Create offer from pc2, apply and rollback on pc1
+ pc2.addTransceiver('audio', { direction: 'recvonly' });
+ const offer2 = await pc2.createOffer();
+ await pc1.setRemoteDescription(offer2);
+ await pc1.setRemoteDescription({type: "rollback"});
+
+ // Then try applying pc1's old offer
+ await pc1.setLocalDescription(offer1);
+ }, `local offer created before setRemoteDescription(remote offer) then rollback should still be usable`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ // We don't use this right away. pc1 has provisionally decided that the
+ // (only) transceiver is bound to level 0.
+ const offer1 = await pc1.createOffer();
+
+ // Create offer from pc2, apply and rollback on pc1
+ pc2.addTransceiver('audio', { direction: 'recvonly' });
+ pc2.addTransceiver('video', { direction: 'recvonly' });
+ const offer2 = await pc2.createOffer();
+ // pc1 now should change its mind about what level its video transceiver is
+ // bound to. It was 0, now it is 1.
+ await pc1.setRemoteDescription(offer2);
+
+ // Rolling back should put things back the way they were.
+ await pc1.setRemoteDescription({type: "rollback"});
+
+ // Then try applying pc1's old offer
+ await pc1.setLocalDescription(offer1);
+ }, "local offer created before setRemoteDescription(remote offer) with different transceiver level assignments then rollback should still be usable");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.getTransceivers().length, 1);
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 0);
+ }, "rollback of a remote offer should remove a transceiver");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.getTransceivers().length, 1);
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ const track = stream2.getVideoTracks()[0];
+ await pc2.getTransceivers()[0].sender.replaceTrack(track);
+
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 0);
+ }, "rollback of a remote offer should remove touched transceiver");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.getTransceivers().length, 1);
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 1);
+ assert_equals(pc2.getTransceivers()[0].mid, null);
+ assert_equals(pc2.getTransceivers()[0].receiver.transport, null);
+ }, "rollback of a remote offer should keep a transceiver");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.getTransceivers().length, 1);
+
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 1);
+ assert_equals(pc2.getTransceivers()[0].mid, null);
+ assert_equals(pc2.getTransceivers()[0].receiver.transport, null);
+ }, "rollback of a remote offer should keep a transceiver created by addtrack");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.getTransceivers().length, 1);
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+ await pc2.getTransceivers()[0].sender.replaceTrack(null);
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 1);
+ }, "rollback of a remote offer should keep a transceiver without tracks");
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc.addTrack(stream.getTracks()[0], stream);
+
+ const states = [];
+ const signalingstatechangeResolver = new Resolver();
+ pc.onsignalingstatechange = () => {
+ states.push(pc.signalingState);
+ signalingstatechangeResolver.resolve();
+ };
+
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ assert_not_equals(pc.getTransceivers()[0].sender.transport, null);
+ await pc.setLocalDescription({type: "rollback"});
+ assert_equals(pc.getTransceivers().length, 1);
+ assert_equals(pc.getTransceivers()[0].mid, null)
+ assert_equals(pc.getTransceivers()[0].sender.transport, null);
+ await pc.setLocalDescription(offer);
+ assert_equals(pc.getTransceivers().length, 1);
+ await signalingstatechangeResolver.promise;
+ assert_array_equals(states, ['have-local-offer', 'stable', 'have-local-offer']);
+ }, "explicit rollback of local offer should remove transceivers and transport");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ const signalingstatechangeResolver = new Resolver();
+ pc1.onsignalingstatechange = () => {
+ states.push(pc1.signalingState);
+ signalingstatechangeResolver.resolve();
+ };
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTransceiver(stream1.getTracks()[0], stream1);
+
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTransceiver(stream2.getTracks()[0], stream2);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ pc1.onnegotiationneeded = t.step_func(() => assert_true(false, "There should be no negotiationneeded event right now"));
+ await pc1.setRemoteDescription(await pc2.createOffer());
+ await pc1.setLocalDescription(await pc1.createAnswer());
+ await signalingstatechangeResolver.promise;
+ assert_array_equals(states, ['have-local-offer', 'stable', 'have-remote-offer', 'stable']);
+ await new Promise(r => pc1.onnegotiationneeded = r);
+ }, "when using addTransceiver, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded until we settle in stable");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const states = [];
+ const signalingstatechangeResolver = new Resolver();
+ pc1.onsignalingstatechange = () => {
+ states.push(pc1.signalingState);
+ signalingstatechangeResolver.resolve();
+ };
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream1.getTracks()[0], stream1);
+
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ pc1.onnegotiationneeded = t.step_func(() => assert_true(false, "There should be no negotiationneeded event in this test"));
+ await pc1.setRemoteDescription(await pc2.createOffer());
+ await pc1.setLocalDescription(await pc1.createAnswer());
+ assert_array_equals(states, ['have-local-offer', 'stable', 'have-remote-offer', 'stable']);
+ await new Promise(r => t.step_timeout(r, 0));
+ }, "when using addTrack, implicit rollback of a local offer should visit stable state, but not fire negotiationneeded");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // In stable state add video on both end and make sure video transceiver is not killed.
+
+ const stream1 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream1.getTracks()[0], stream1);
+ await pc1.setLocalDescription(await pc1.createOffer());
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+ const offer2 = await pc2.createOffer();
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 2);
+ await pc2.setLocalDescription(offer2);
+ }, "rollback of a remote offer to negotiated stable state should enable " +
+ "applying of a local offer");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // Both ends want to add video at the same time. pc2 rolls back.
+
+ const stream2 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+ await pc2.setLocalDescription(await pc2.createOffer());
+ assert_equals(pc2.getTransceivers().length, 2);
+ assert_not_equals(pc2.getTransceivers()[1].sender.transport, null);
+ await pc2.setLocalDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 2);
+ // Rollback didn't touch audio transceiver and transport is intact.
+ assert_not_equals(pc2.getTransceivers()[0].sender.transport, null);
+ // Video transport got killed.
+ assert_equals(pc2.getTransceivers()[1].sender.transport, null);
+ const stream1 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream1.getTracks()[0], stream1);
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+ }, "rollback of a local offer to negotiated stable state should enable " +
+ "applying of a remote offer");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream.getTracks()[0], stream);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // pc1 adds video and pc2 adds audio. pc2 rolls back.
+ assert_equals(pc2.getTransceivers()[0].direction, "recvonly");
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc2.addTrack(stream2.getTracks()[0], stream2);
+ assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
+ await pc2.setLocalDescription(await pc2.createOffer());
+ assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
+ await pc2.setLocalDescription({type: "rollback"});
+ assert_equals(pc2.getTransceivers().length, 1);
+ // setLocalDescription didn't change direction. So direction remains "sendrecv"
+ assert_equals(pc2.getTransceivers()[0].direction, "sendrecv");
+ // Rollback didn't touch audio transceiver and transport is intact. Still can receive audio.
+ assert_not_equals(pc2.getTransceivers()[0].receiver.transport, null);
+ const stream1 = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream1.getTracks()[0], stream1);
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+ }, "rollback a local offer with audio direction change to negotiated " +
+ "stable state and then add video receiver");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver('video', {direction: 'sendonly'});
+ pc2.addTransceiver('video', {direction: 'sendonly'});
+ await pc1.setLocalDescription(await pc1.createOffer());
+ const pc1FirstMid = pc1.getTransceivers()[0].mid;
+ await pc2.setLocalDescription(await pc2.createOffer());
+ const pc2FirstMid = pc2.getTransceivers()[0].mid;
+ // I don't think it is mandated that this has to be true, but any implementation I know of would
+ // have predictable mids (e.g. 0, 1, 2...) so pc1 and pc2 should offer with the same mids.
+ assert_equals(pc1FirstMid, pc2FirstMid);
+ await pc1.setRemoteDescription(pc2.pendingLocalDescription);
+ // We've implicitly rolled back and the SRD caused a second transceiver to be created.
+ // As such, the first transceiver's mid will now be null, and the second transceiver's mid will
+ // match the remote offer.
+ assert_equals(pc1.getTransceivers().length, 2);
+ assert_equals(pc1.getTransceivers()[0].mid, null);
+ assert_equals(pc1.getTransceivers()[1].mid, pc2FirstMid);
+ // If we now do an offer the first transceiver will get a different mid than in the first
+ // pc1.createOffer()!
+ pc1.setLocalDescription(await pc1.createAnswer());
+ await pc1.setLocalDescription(await pc1.createOffer());
+ assert_not_equals(pc1.getTransceivers()[0].mid, pc1FirstMid);
+ }, "two transceivers with same mids");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const audio = stream.getAudioTracks()[0];
+ pc1.addTrack(audio, stream);
+ const video = stream.getVideoTracks()[0];
+ pc1.addTrack(video, stream);
+
+ let remoteStream = null;
+ pc2.ontrack = e => { remoteStream = e.streams[0]; }
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_true(remoteStream != null);
+ let remoteTracks = remoteStream.getTracks();
+ const removedTracks = [];
+ remoteStream.onremovetrack = e => { removedTracks.push(e.track.id); }
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(removedTracks.length, 2,
+ "Rollback should have removed two tracks");
+ assert_true(removedTracks.includes(remoteTracks[0].id),
+ "First track should be removed");
+ assert_true(removedTracks.includes(remoteTracks[1].id),
+ "Second track should be removed");
+
+ }, "onremovetrack fires during remote rollback");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ pc1.addTrack(stream1.getTracks()[0], stream1);
+
+ const offer1 = await pc1.createOffer();
+
+ const remoteStreams = [];
+ pc2.ontrack = e => { remoteStreams.push(e.streams[0]); }
+
+ await pc1.setLocalDescription(offer1);
+ await pc2.setRemoteDescription(pc1.pendingLocalDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ assert_equals(remoteStreams.length, 1, "Number of remote streams");
+ assert_equals(remoteStreams[0].getTracks().length, 1, "Number of remote tracks");
+ const track = remoteStreams[0].getTracks()[0];
+
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ pc1.getTransceivers()[0].sender.setStreams(stream2);
+
+ const offer2 = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer2);
+
+ assert_equals(remoteStreams.length, 2);
+ assert_equals(remoteStreams[0].getTracks().length, 0);
+ assert_equals(remoteStreams[1].getTracks()[0].id, track.id);
+ await pc2.setRemoteDescription({type: "rollback"});
+ assert_equals(remoteStreams.length, 3);
+ assert_equals(remoteStreams[0].id, remoteStreams[2].id);
+ assert_equals(remoteStreams[1].getTracks().length, 0);
+ assert_equals(remoteStreams[2].getTracks().length, 1);
+ assert_equals(remoteStreams[2].getTracks()[0].id, track.id);
+
+ }, "rollback of a remote offer with stream changes");
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc2.addTransceiver('audio');
+ const offer = await pc2.createOffer();
+ await pc1.setRemoteDescription(offer);
+ const [transceiver] = pc1.getTransceivers();
+ pc1.setRemoteDescription({type:'rollback'});
+ pc1.removeTrack(transceiver.sender);
+ }, 'removeTrack() with a sender being rolled back does not crash or throw');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver('video');
+ const channel = pc2.createDataChannel('dummy');
+ await pc2.setLocalDescription(await pc2.createOffer());
+ await pc2.setRemoteDescription(await pc1.createOffer());
+ assert_equals(pc2.signalingState, 'have-remote-offer');
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await pc2.setLocalDescription(await pc2.createOffer());
+ assert_equals(channel.readyState, 'connecting');
+ }, 'Implicit rollback with only a datachannel works');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.setRemoteDescription - add/remove remote tracks</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // addEventListenerPromise
+ // exchangeOffer
+ // exchangeOfferAnswer
+ // Resolver
+
+ // These tests are concerned with the observable consequences of processing
+ // the addition or removal of remote tracks, including events firing and the
+ // states of RTCPeerConnection, MediaStream and MediaStreamTrack.
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ caller.addTrack(localStream.getTracks()[0]);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_equals(e.streams.length, 0, 'No remote stream created.');
+ });
+ await exchangeOffer(caller, callee);
+ await ontrackPromise;
+ }, 'addTrack() with a track and no stream makes ontrack fire with a track and no stream.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ caller.addTrack(localStream.getTracks()[0], localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_equals(e.streams.length, 1, 'Created a single remote stream.');
+ assert_equals(e.streams[0].id, localStream.id,
+ 'Local and remote stream IDs match.');
+ assert_array_equals(e.streams[0].getTracks(), [e.track],
+ 'The remote stream contains the remote track.');
+ });
+ await exchangeOffer(caller, callee);
+ await ontrackPromise;
+ }, 'addTrack() with a track and a stream makes ontrack fire with a track and a stream.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let eventSequence = '';
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ caller.addTrack(localStream.getTracks()[0], localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ eventSequence += 'ontrack;';
+ });
+ await exchangeOffer(caller, callee);
+ eventSequence += 'setRemoteDescription;';
+ await ontrackPromise;
+ assert_equals(eventSequence, 'ontrack;setRemoteDescription;');
+ }, 'ontrack fires before setRemoteDescription resolves.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStreams = await Promise.all([
+ getNoiseStream({audio: true}),
+ getNoiseStream({audio: true}),
+ ]);
+ t.add_cleanup(() => localStreams.forEach((stream) =>
+ stream.getTracks().forEach((track) => track.stop())));
+ caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
+ caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
+ let ontrackEventsFired = 0;
+ const ontrackEventResolvers = [ new Resolver(), new Resolver() ];
+ callee.ontrack = t.step_func(e => {
+ ontrackEventResolvers[ontrackEventsFired++].resolve(e);
+ });
+ await exchangeOffer(caller, callee);
+ let firstTrackEvent = await ontrackEventResolvers[0];
+ assert_equals(firstTrackEvent.streams.length, 1,
+ 'First ontrack fires with a single stream.');
+ assert_equals(firstTrackEvent.streams[0].id,
+ localStreams[0].id,
+ 'First ontrack\'s stream ID matches local stream.');
+ let secondTrackEvent = await ontrackEventResolvers[1];
+ assert_equals(secondTrackEvent.streams.length, 1,
+ 'Second ontrack fires with a single stream.');
+ assert_equals(secondTrackEvent.streams[0].id,
+ localStreams[0].id,
+ 'Second ontrack\'s stream ID matches local stream.');
+ assert_array_equals(firstTrackEvent.streams, secondTrackEvent.streams,
+ 'ontrack was fired with the same streams both times.');
+
+ assert_equals(firstTrackEvent.streams[0].getTracks().length, 2, "stream should have two tracks");
+ assert_true(firstTrackEvent.streams[0].getTracks().includes(firstTrackEvent.track), "remoteStream should have the first track");
+ assert_true(firstTrackEvent.streams[0].getTracks().includes(secondTrackEvent.track), "remoteStream should have the second track");
+ assert_equals(ontrackEventsFired, 2, 'Unexpected number of track events.');
+
+ assert_equals(ontrackEventsFired, 2, 'Unexpected number of track events.');
+ }, 'addTrack() with two tracks and one stream makes ontrack fire twice with the tracks and shared stream.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let eventSequence = '';
+ const localStreams = await Promise.all([
+ getNoiseStream({audio: true}),
+ getNoiseStream({audio: true}),
+ ]);
+ t.add_cleanup(() => localStreams.forEach((stream) =>
+ stream.getTracks().forEach((track) => track.stop())));
+ caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
+ const remoteStreams = [];
+ callee.ontrack = e => {
+ if (!remoteStreams.includes(e.streams[0]))
+ remoteStreams.push(e.streams[0]);
+ };
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ assert_equals(remoteStreams.length, 1, 'One remote stream created.');
+ assert_equals(remoteStreams[0].id, localStreams[0].id,
+ 'First local and remote streams have the same ID.');
+ const firstRemoteTrack = remoteStreams[0].getTracks()[0];
+ const onaddtrackPromise = addEventListenerPromise(t, remoteStreams[0], 'addtrack');
+ caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
+ await exchangeOffer(caller, callee);
+ const e = await onaddtrackPromise;
+ assert_equals(remoteStreams[0].getTracks().length, 2, 'stream has two tracks');
+ assert_not_equals(e.track.id, firstRemoteTrack.id,
+ 'addtrack event has a new track');
+ assert_equals(remoteStreams.length, 1, 'Still a single remote stream.');
+ }, 'addTrack() for an existing stream makes stream.onaddtrack fire.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let eventSequence = '';
+ const localStreams = await Promise.all([
+ getNoiseStream({audio: true}),
+ getNoiseStream({audio: true}),
+ ]);
+ t.add_cleanup(() => localStreams.forEach((stream) =>
+ stream.getTracks().forEach((track) => track.stop())));
+ caller.addTrack(localStreams[0].getTracks()[0], localStreams[0]);
+ const remoteStreams = [];
+ callee.ontrack = e => {
+ if (!remoteStreams.includes(e.streams[0]))
+ remoteStreams.push(e.streams[0]);
+ };
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ assert_equals(remoteStreams.length, 1, 'One remote stream created.');
+ const onaddtrackPromise =
+ addEventListenerPromise(t, remoteStreams[0], 'addtrack', e => {
+ eventSequence += 'stream.onaddtrack;';
+ });
+ caller.addTrack(localStreams[1].getTracks()[0], localStreams[0]);
+ await exchangeOffer(caller, callee);
+ eventSequence += 'setRemoteDescription;';
+ await onaddtrackPromise;
+ assert_equals(remoteStreams.length, 1, 'Still a single remote stream.');
+ assert_equals(eventSequence, 'stream.onaddtrack;setRemoteDescription;');
+ }, 'stream.onaddtrack fires before setRemoteDescription resolves.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStreams = await Promise.all([
+ getNoiseStream({audio: true}),
+ getNoiseStream({audio: true}),
+ ]);
+ t.add_cleanup(() => localStreams.forEach((stream) =>
+ stream.getTracks().forEach((track) => track.stop())));
+ caller.addTrack(localStreams[0].getTracks()[0],
+ localStreams[0], localStreams[1]);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_equals(e.streams.length, 2, 'Two remote stream created.');
+ assert_array_equals(e.streams[0].getTracks(), [e.track],
+ 'First remote stream == [remote track].');
+ assert_array_equals(e.streams[1].getTracks(), [e.track],
+ 'Second remote stream == [remote track].');
+ assert_equals(e.streams[0].id, localStreams[0].id,
+ 'First local and remote stream IDs match.');
+ assert_equals(e.streams[1].id, localStreams[1].id,
+ 'Second local and remote stream IDs match.');
+ });
+ await exchangeOffer(caller, callee);
+ await ontrackPromise;
+ }, 'addTrack() with a track and two streams makes ontrack fire with a track and two streams.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ caller.addTrack(localStream.getTracks()[0], localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_array_equals(callee.getReceivers(), [e.receiver],
+ 'getReceivers() == [e.receiver].');
+ });
+ await exchangeOffer(caller, callee);
+ await ontrackPromise;
+ }, 'ontrack\'s receiver matches getReceivers().');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ const sender = caller.addTrack(localStream.getTracks()[0], localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track');
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await ontrackPromise;
+ assert_equals(callee.getReceivers().length, 1, 'One receiver created.');
+ caller.removeTrack(sender);
+ await exchangeOffer(caller, callee);
+ assert_equals(callee.getReceivers().length, 1, 'Receiver not removed.');
+ }, 'removeTrack() does not remove the receiver.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ const [track] = localStream.getTracks();
+ const sender = caller.addTrack(track, localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_equals(e.streams.length, 1);
+ return e.streams[0];
+ });
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ const remoteStream = await ontrackPromise;
+ const remoteTrack = remoteStream.getTracks()[0];
+ const onremovetrackPromise =
+ addEventListenerPromise(t, remoteStream, 'removetrack', e => {
+ assert_equals(e.track, remoteTrack);
+ assert_equals(remoteStream.getTracks().length, 0,
+ 'Remote stream emptied of tracks.');
+ });
+ caller.removeTrack(sender);
+ await exchangeOffer(caller, callee);
+ await onremovetrackPromise;
+ }, 'removeTrack() makes stream.onremovetrack fire and the track to be removed from the stream.');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let eventSequence = '';
+ const localStream =
+ await getNoiseStream({audio: true});
+ t.add_cleanup(() => localStream.getTracks().forEach(track => track.stop()));
+ const sender = caller.addTrack(localStream.getTracks()[0], localStream);
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track', e => {
+ assert_equals(e.streams.length, 1);
+ return e.streams[0];
+ });
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ const remoteStream = await ontrackPromise;
+ const remoteTrack = remoteStream.getTracks()[0];
+ const onremovetrackPromise =
+ addEventListenerPromise(t, remoteStream, 'removetrack', e => {
+ eventSequence += 'stream.onremovetrack;';
+ });
+ caller.removeTrack(sender);
+ await exchangeOffer(caller, callee);
+ eventSequence += 'setRemoteDescription;';
+ await onremovetrackPromise;
+ assert_equals(eventSequence, 'stream.onremovetrack;setRemoteDescription;');
+ }, 'stream.onremovetrack fires before setRemoteDescription resolves.');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const sender = pc.addTrack(stream.getTracks()[0]);
+ pc.removeTrack(sender);
+ pc.removeTrack(sender);
+ }, 'removeTrack() twice is safe.');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.setRemoteDescription</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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:
+ // assert_session_desc_not_similar()
+ // assert_session_desc_similar()
+
+ /*
+ 4.3.2. Interface Definition
+ [Constructor(optional RTCConfiguration configuration)]
+ interface RTCPeerConnection : EventTarget {
+ Promise<void> setRemoteDescription(
+ RTCSessionDescriptionInit description);
+
+ readonly attribute RTCSessionDescription? remoteDescription;
+ readonly attribute RTCSessionDescription? currentRemoteDescription;
+ readonly attribute RTCSessionDescription? pendingRemoteDescription;
+ ...
+ };
+
+ 4.6.2. RTCSessionDescription Class
+ dictionary RTCSessionDescriptionInit {
+ required RTCSdpType type;
+ DOMString sdp = "";
+ };
+
+ 4.6.1. RTCSdpType
+ enum RTCSdpType {
+ "offer",
+ "pranswer",
+ "answer",
+ "rollback"
+ };
+ */
+
+ /*
+ 4.6.1. enum RTCSdpType
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ // SDP is validated after WebIDL validation
+ try {
+ await pc.setRemoteDescription({ type: 'bogus', sdp: 'bogus' });
+ t.unreached_func("Should have rejected.");
+ } catch (e) {
+ assert_throws_js(TypeError, () => { throw e });
+ }
+ }, 'setRemoteDescription with invalid type and invalid SDP should reject with TypeError');
+
+ /* Dedicated signalingstate events test. */
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ t.add_cleanup(() => pc2.close());
+
+ let eventCount = 0;
+ const states = [
+ 'stable', 'have-local-offer', 'stable', 'have-remote-offer',
+ ];
+ pc.onsignalingstatechange = t.step_func(() =>
+ assert_equals(pc.signalingState, states[++eventCount]));
+
+ const assert_state = state => {
+ assert_equals(state, pc.signalingState);
+ assert_equals(state, states[eventCount]);
+ };
+
+ const offer = await generateAudioReceiveOnlyOffer(pc);
+ assert_state('stable');
+ await pc.setLocalDescription(offer);
+ assert_state('have-local-offer');
+ await pc2.setRemoteDescription(offer);
+ await exchangeAnswer(pc, pc2);
+ assert_state('stable');
+ await exchangeOffer(pc2, pc);
+ assert_state('have-remote-offer');
+ }, 'Negotiation should fire signalingsstate events');
+
+ /* Operations after returning to stable state */
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ t.add_cleanup(() => pc2.close());
+
+ const offer1 = await generateAudioReceiveOnlyOffer(pc2);
+ await pc2.setLocalDescription(offer1);
+ await pc.setRemoteDescription(offer1);
+ await exchangeAnswer(pc2, pc);
+ const offer2 = await generateVideoReceiveOnlyOffer(pc2);
+ await pc2.setLocalDescription(offer2);
+ await pc.setRemoteDescription(offer2);
+ assert_session_desc_not_similar(offer1, offer2);
+ assert_session_desc_similar(pc.remoteDescription, offer2);
+ assert_session_desc_similar(pc.currentRemoteDescription, offer1);
+ assert_session_desc_similar(pc.pendingRemoteDescription, offer2);
+ }, 'Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ t.add_cleanup(() => pc2.close());
+
+ const offer = await generateAudioReceiveOnlyOffer(pc);
+ await pc.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc.setRemoteDescription(answer);
+ await exchangeOffer(pc2, pc);
+ assert_equals(pc.remoteDescription.sdp, pc.pendingRemoteDescription.sdp);
+ assert_session_desc_similar(pc.remoteDescription, offer);
+ assert_session_desc_similar(pc.currentRemoteDescription, answer);
+ }, 'Switching role from offerer to answerer after going back to stable state should succeed');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const offer = await pc.createOffer();
+ const p = Promise.race([
+ pc.setRemoteDescription(offer),
+ new Promise(r => t.step_timeout(() => r("timeout"), 200))
+ ]);
+ pc.close();
+ assert_equals(await p, "timeout");
+ assert_equals(pc.signalingState, "closed", "In closed state");
+ }, 'Closing on setRemoteDescription() neither resolves nor rejects');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ const p = Promise.race([
+ pc.setRemoteDescription(offer),
+ new Promise(r => t.step_timeout(() => r("timeout"), 200))
+ ]);
+ pc.close();
+ assert_equals(await p, "timeout");
+ assert_equals(pc.signalingState, "closed", "In closed state");
+ }, 'Closing on rollback neither resolves nor rejects');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection.prototype.getStats</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCStats-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // exchangeOfferAnswer
+ // getUserMediaTracksAndStreams
+ // waitForRtpAndRtcpStats
+
+ // The following helper functions are called from RTCStats-helper.js
+ // (depends on dictionary-helper.js):
+ // validateRtcStats
+
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ let track;
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ track = tracks[0];
+ pc.addTrack(track, streams[0]);
+ return pc.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', track.id);
+ assert_true(trackStats != null, 'Has stats for track');
+ // TODO(hbos): Here and elsewhere, validateRtcStats() only tests id,
+ // timestamp and type is correct type. Should validate based on stats type
+ // but it expects both audio and video members.
+ // https://github.com/web-platform-tests/wpt/issues/9010
+ validateRtcStats(report, trackStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'addTrack() without setLocalDescription() yields track stats');
+
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ let track;
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ track = tracks[0];
+ pc.addTrack(track, streams[0]);
+ return pc.createOffer();
+ }))
+ .then(t.step_func(offer => {
+ return pc.setLocalDescription(offer);
+ }))
+ .then(t.step_func(() => {
+ return pc.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', track.id);
+ assert_true(trackStats != null, 'Has stats for track');
+ validateRtcStats(report, trackStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'addTrack() with setLocalDescription() yields track stats');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let sendingTrack;
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ sendingTrack = tracks[0];
+ caller.addTrack(sendingTrack, streams[0]);
+ return exchangeOfferAnswer(caller, callee);
+ }))
+ .then(t.step_func(() => {
+ return caller.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack.id);
+ assert_true(trackStats != null, 'Has stats for sending track');
+ let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
+ 'trackId', trackStats.id);
+ assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
+ validateRtcStats(report, trackStats);
+ validateRtcStats(report, outboundStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'O/A exchange yields outbound RTP stream stats for sending track');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let receivingTrack;
+ callee.ontrack = trackEvent => {
+ assert_equals(receivingTrack, undefined, 'ontrack has not fired before');
+ receivingTrack = trackEvent.track;
+ };
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ caller.addTrack(tracks[0], streams[0]);
+ return exchangeOfferAnswer(caller, callee);
+ }))
+ .then(t.step_func(() => {
+ return callee.getStats();
+ }))
+ .then(t.step_func(report => {
+ assert_true(receivingTrack != null, 'Has a receiving track');
+ let trackStats = findStatsByTypeAndId(report, 'track', receivingTrack.id);
+ assert_true(trackStats != null, 'Has stats for receiving track');
+ let inboundStats = findStatsByTypeAndMember(report, 'inbound-rtp',
+ 'trackId', trackStats.id);
+ assert_true(inboundStats != null, 'Has stats for outbound RTP stream');
+ validateRtcStats(report, trackStats);
+ validateRtcStats(report, inboundStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'O/A exchange yields inbound RTP stream stats for receiving track');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let sendingTrack1;
+ let sendingTrack2;
+ let sender;
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ sendingTrack1 = tracks[0];
+ sendingTrack2 = tracks[1];
+ sender = caller.addTrack(sendingTrack1, streams[0]);
+ return sender.replaceTrack(sendingTrack2);
+ }))
+ .then(t.step_func(() => {
+ return caller.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
+ assert_true(trackStats != null, 'Has stats for replaced track');
+ validateRtcStats(report, trackStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() before offer: new track attachment stats present');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let sendingTrack1;
+ let sendingTrack2;
+ let sender;
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ sendingTrack1 = tracks[0];
+ sendingTrack2 = tracks[1];
+ sender = caller.addTrack(sendingTrack1, streams[0]);
+ return exchangeOffer(caller, callee);
+ }))
+ .then(t.step_func(() => {
+ return sender.replaceTrack(sendingTrack2);
+ }))
+ .then(t.step_func(() => {
+ return caller.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
+ assert_true(trackStats != null, 'Has stats for replaced track');
+ let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
+ 'trackId', trackStats.id);
+ assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
+ validateRtcStats(report, trackStats);
+ validateRtcStats(report, outboundStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() after offer, before answer: new track attachment stats ' +
+ 'present');
+
+ async_test(t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let sendingTrack1;
+ let sendingTrack2;
+ let sender;
+ getUserMediaTracksAndStreams(2)
+ .then(t.step_func(([tracks, streams]) => {
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ sendingTrack1 = tracks[0];
+ sendingTrack2 = tracks[1];
+ sender = caller.addTrack(sendingTrack1, streams[0]);
+ return exchangeOfferAnswer(caller, callee);
+ }))
+ .then(t.step_func(() => {
+ return sender.replaceTrack(sendingTrack2);
+ }))
+ .then(t.step_func(() => {
+ return caller.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', sendingTrack2.id);
+ assert_true(trackStats != null, 'Has stats for replaced track');
+ let outboundStats = findStatsByTypeAndMember(report, 'outbound-rtp',
+ 'trackId', trackStats.id);
+ assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
+ validateRtcStats(report, trackStats);
+ validateRtcStats(report, outboundStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'replaceTrack() after answer: new track attachment stats present');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ let sender = caller.addTrack(tracks[0], streams[0]);
+ callee.addTrack(tracks[1], streams[1]);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await listenToConnected(caller);
+ let receiver = caller.getReceivers()[0];
+
+ // Obtain inbound and outbound RTP stream stats on a full stats report.
+ let fullReport = await caller.getStats();
+ let outboundTrackStats = findStatsByTypeAndId(
+ fullReport, 'track', sender.track.id);
+ let outboundStats = findStatsByTypeAndMember(
+ fullReport, 'outbound-rtp', 'trackId', outboundTrackStats.id);
+ assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
+ let inboundTrackStats = findStatsByTypeAndId(
+ fullReport, 'track', receiver.track.id);
+ let inboundStats = findStatsByTypeAndMember(
+ fullReport, 'inbound-rtp', 'trackId', inboundTrackStats.id);
+ assert_true(inboundStats != null, 'Has stats for inbound RTP stream');
+
+ // Perform stats selection algorithm with sender selector. The result should
+ // contain the outbound-rtp but not the inbound-rtp.
+ let senderReport = await sender.getStats();
+ assert_true(senderReport.has(outboundStats.id));
+ assert_false(senderReport.has(inboundStats.id));
+
+ // Validate the stats graph, ensuring all stats objects are reachable and
+ // valid from the outbound-rtp stats.
+ validateStatsGraph(senderReport, senderReport.get(outboundStats.id));
+ // Ensure that the stats graph contains some expected dictionaries.
+ assert_equals(findStatsOfType(senderReport, 'track').length, 1,
+ 'senderReport should contain track stats');
+ assert_equals(findStatsOfType(senderReport, 'transport').length, 1,
+ 'senderReport should contain transport stats');
+ assert_equals(findStatsOfType(senderReport, 'candidate-pair').length, 1,
+ 'senderReport should contain candidate-pair stats');
+ assert_equals(findStatsOfType(senderReport, 'local-candidate').length, 1,
+ 'senderReport should contain local-candidate stats');
+ assert_equals(findStatsOfType(senderReport, 'remote-candidate').length, 1,
+ 'senderReport should contain remote-candidate stats');
+ }, 'RTCRtpSender.getStats() contains only outbound-rtp and related stats');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ let sender = caller.addTrack(tracks[0], streams[0]);
+ callee.addTrack(tracks[1], streams[1]);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await listenToConnected(caller);
+ let receiver = caller.getReceivers()[0];
+
+ // Obtain inbound and outbound RTP stream stats on a full stats report.
+ let fullReport = await caller.getStats();
+ let outboundTrackStats = findStatsByTypeAndId(
+ fullReport, 'track', sender.track.id);
+ let outboundStats = findStatsByTypeAndMember(
+ fullReport, 'outbound-rtp', 'trackId', outboundTrackStats.id);
+ assert_true(outboundStats != null, 'Has stats for outbound RTP stream');
+ let inboundTrackStats = findStatsByTypeAndId(
+ fullReport, 'track', receiver.track.id);
+ let inboundStats = findStatsByTypeAndMember(
+ fullReport, 'inbound-rtp', 'trackId', inboundTrackStats.id);
+ assert_true(inboundStats != null, 'Has stats for inbound RTP stream');
+
+ // Perform stats selection algorithm with receiver selector. The result
+ // should contain the inbound-rtp but not the outbound-rtp.
+ let receiverReport = await receiver.getStats();
+ assert_true(receiverReport.has(inboundStats.id));
+ assert_false(receiverReport.has(outboundStats.id));
+
+ // Validate the stats graph, ensuring all stats objects are reachable and
+ // valid from the outbound-rtp stats.
+ validateStatsGraph(receiverReport, receiverReport.get(inboundStats.id));
+ // Ensure that the stats graph contains some expected dictionaries.
+ assert_equals(findStatsOfType(receiverReport, 'track').length, 1,
+ 'receiverReport should contain track stats');
+ assert_equals(findStatsOfType(receiverReport, 'transport').length, 1,
+ 'receiverReport should contain transport stats');
+ assert_equals(findStatsOfType(receiverReport, 'candidate-pair').length, 1,
+ 'receiverReport should contain candidate-pair stats');
+ assert_equals(findStatsOfType(receiverReport, 'local-candidate').length, 1,
+ 'receiverReport should contain local-candidate stats');
+ assert_equals(findStatsOfType(receiverReport, 'remote-candidate').length, 1,
+ 'receiverReport should contain remote-candidate stats');
+ }, 'RTCRtpReceiver.getStats() contains only inbound-rtp and related stats');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ let sender = caller.addTrack(tracks[0], streams[0]);
+ callee.addTrack(tracks[1], streams[1]);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await listenToIceConnected(caller);
+
+ // Wait until RTCP has arrived so that it can not arrive between
+ // the two get stats calls.
+ await waitForRtpAndRtcpStats(caller);
+
+ let senderReport = await sender.getStats();
+ let trackReport = await caller.getStats(sender.track);
+
+ // Verify the same stats objects are returned but don't compare each
+ // individual metric because timestamps and counters could have gone up
+ // between the two getStats() calls.
+ senderReport.forEach(senderReportStat => {
+ assert_true(trackReport.has(senderReportStat.id));
+ });
+ trackReport.forEach(trackReportStat => {
+ assert_true(senderReport.has(trackReportStat.id));
+ });
+ }, 'RTCPeerConnection.getStats(sendingTrack) is the same as ' +
+ 'RTCRtpSender.getStats()');
+
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ let sender = caller.addTrack(tracks[0], streams[0]);
+ callee.addTrack(tracks[1], streams[1]);
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAnswer(caller, callee);
+ await listenToIceConnected(caller);
+ let receiver = caller.getReceivers()[0];
+
+ // Wait until RTCP has arrived so that it can not arrive between
+ // the two get stats calls.
+ await waitForRtpAndRtcpStats(caller);
+
+ let receiverReport = await receiver.getStats();
+ let trackReport = await caller.getStats(receiver.track);
+
+ // Verify the same stats objects are returned but don't compare each
+ // individual metric because timestamps and counters could have gone up
+ // between the two getStats() calls.
+ receiverReport.forEach(receiverReportStat => {
+ assert_true(trackReport.has(receiverReportStat.id));
+ });
+ trackReport.forEach(trackReportStat => {
+ assert_true(receiverReport.has(trackReportStat.id));
+ });
+ }, 'RTCPeerConnection.getStats(receivingTrack) is the same as ' +
+ 'RTCRtpReceiver.getStats()');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(1);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(tracks[0]));
+ }, 'RTCPeerConnection.getStats(track) throws InvalidAccessError when there ' +
+ 'are zero senders or receivers for the track');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ let [tracks, streams] = await getUserMediaTracksAndStreams(2);
+ t.add_cleanup(() => tracks.forEach(track => track.stop()));
+ let sender1 = pc.addTrack(tracks[0], streams[0]);
+ let sender2 = pc.addTrack(tracks[1], streams[1]);
+ await sender2.replaceTrack(sender1.track);
+ await promise_rejects_dom(t, 'InvalidAccessError', pc.getStats(sender1.track));
+ }, 'RTCPeerConnection.getStats(track) throws InvalidAccessError when there ' +
+ 'are multiple senders for the track');
+
+ // Helpers.
+
+ function findStatsByTypeAndId(report, type, identifier) {
+ return findStats(report, stats => {
+ return stats.type == type && stats[type + 'Identifier'] == identifier;
+ });
+ }
+
+ function findStatsByTypeAndMember(report, type, member, value) {
+ return findStats(report, stats => {
+ return stats.type == type && stats[member] == value;
+ });
+ }
+
+ function findStats(report, findFunc) {
+ for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
+ if (findFunc(n.value))
+ return n.value;
+ }
+ return null;
+ }
+
+ function findStatsOfType(report, type) {
+ let stats = [];
+ for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
+ if (n.value.type == type)
+ stats.push(n.value);
+ }
+ return stats;
+ }
+
+ // Explores the stats graph starting from |stat|, validating each stat
+ // (validateRtcStats) and asserting that all stats of the report were visited.
+ function validateStatsGraph(report, stat) {
+ let visitedIds = new Set();
+ validateStatsGraphRecursively(report, stat.id, visitedIds);
+ assert_equals(visitedIds.size, report.size,
+ 'Entire stats graph should have been explored.')
+ }
+
+ function validateStatsGraphRecursively(report, currentId, visitedIds) {
+ if (visitedIds.has(currentId))
+ return;
+ visitedIds.add(currentId);
+ assert_true(report.has(currentId), 'Broken reference.');
+ let stat = report.get(currentId);
+ validateRtcStats(report, stat);
+ for (let member in stat) {
+ if (member.endsWith('Id')) {
+ validateStatsGraphRecursively(report, stat[member], visitedIds);
+ } else if (member.endsWith('Ids')) {
+ let ids = stat[member];
+ for (let i = 0; i < ids.length; ++i) {
+ validateStatsGraphRecursively(report, ids[i], visitedIds);
+ }
+ }
+ }
+ }
+</script>
--- /dev/null
+<!doctype html>
+<meta name="timeout" content="long"/>
+<meta charset=utf-8>
+<title>RTCPeerConnection-transceivers.https.html</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// exchangeOffer
+// exchangeOfferAndListenToOntrack
+// exchangeAnswer
+// exchangeAnswerAndListenToOntrack
+// addEventListenerPromise
+// createPeerConnectionWithCleanup
+// createTrackAndStreamWithCleanup
+// findTransceiverForSender
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const sender = pc.addTrack(track, stream);
+ const transceiver = findTransceiverForSender(pc, sender);
+ assert_true(transceiver instanceof RTCRtpTransceiver);
+ assert_true(transceiver.sender instanceof RTCRtpSender);
+ assert_equals(transceiver.sender, sender);
+}, 'addTrack: creates a transceiver for the sender');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_array_equals(pc.getTransceivers(), [transceiver],
+ 'pc.getTransceivers() equals [transceiver]');
+ assert_array_equals(pc.getSenders(), [transceiver.sender],
+ 'pc.getSenders() equals [transceiver.sender]');
+ assert_array_equals(pc.getReceivers(), [transceiver.receiver],
+ 'pc.getReceivers() equals [transceiver.receiver]');
+}, 'addTrack: "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_true(transceiver.sender.track instanceof MediaStreamTrack,
+ 'transceiver.sender.track instanceof MediaStreamTrack');
+ assert_equals(transceiver.sender.track, track,
+ 'transceiver.sender.track == track');
+}, 'addTrack: transceiver.sender is associated with the track');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_true(transceiver.receiver instanceof RTCRtpReceiver,
+ 'transceiver.receiver instanceof RTCRtpReceiver');
+ assert_true(transceiver.receiver.track instanceof MediaStreamTrack,
+ 'transceiver.receiver.track instanceof MediaStreamTrack');
+ assert_not_equals(transceiver.receiver.track, track,
+ 'transceiver.receiver.track != track');
+}, 'addTrack: transceiver.receiver has its own track');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_true(transceiver.receiver.track.muted);
+}, 'addTrack: transceiver.receiver\'s track is muted');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_equals(transceiver.mid, null);
+}, 'addTrack: transceiver is not associated with an m-section');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
+ assert_false(transceiver.stopped);
+}, 'addTrack: transceiver is not stopped');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_equals(transceiver.direction, 'sendrecv');
+}, 'addTrack: transceiver\'s direction is sendrecv');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ assert_equals(transceiver.currentDirection, null);
+}, 'addTrack: transceiver\'s currentDirection is null');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ await pc.setLocalDescription(await pc.createOffer());
+ assert_not_equals(transceiver.mid, null, 'transceiver.mid != null');
+}, 'setLocalDescription(offer): transceiver gets associated with an m-section');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc, pc.addTrack(track, stream));
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ let sdp = offer.sdp;
+ let sdpMidLineStart = sdp.indexOf('a=mid:');
+ let sdpMidLineEnd = sdp.indexOf('\r\n', sdpMidLineStart);
+ assert_true(sdpMidLineStart != -1 && sdpMidLineEnd != -1,
+ 'Failed to parse offer SDP for a=mid');
+ let parsedMid = sdp.substring(sdpMidLineStart + 6, sdpMidLineEnd);
+ assert_equals(transceiver.mid, parsedMid, 'transceiver.mid == parsedMid');
+}, 'setLocalDescription(offer): transceiver.mid matches the offer SDP');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_true(trackEvent instanceof RTCTrackEvent,
+ 'trackEvent instanceof RTCTrackEvent');
+ assert_true(trackEvent.track instanceof MediaStreamTrack,
+ 'trackEvent.track instanceof MediaStreamTrack');
+}, 'setRemoteDescription(offer): ontrack fires with a track');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ pc1.addTrack(track, stream);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_true(trackEvent.track instanceof MediaStreamTrack,
+ 'trackEvent.track instanceof MediaStreamTrack');
+ assert_equals(trackEvent.streams.length, 1,
+ 'trackEvent contains a single stream');
+ assert_true(trackEvent.streams[0] instanceof MediaStream,
+ 'trackEvent has a MediaStream');
+ assert_equals(trackEvent.streams[0].id, stream.id,
+ 'trackEvent.streams[0].id == stream.id');
+}, 'setRemoteDescription(offer): ontrack\'s stream.id is the same as stream.id');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_true(trackEvent.transceiver instanceof RTCRtpTransceiver,
+ 'trackEvent.transceiver instanceof RTCRtpTransceiver');
+}, 'setRemoteDescription(offer): ontrack fires with a transceiver.');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(transceiver.mid, trackEvent.transceiver.mid);
+}, 'setRemoteDescription(offer): transceiver.mid is the same on both ends');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ const transceiver = trackEvent.transceiver;
+ assert_array_equals(pc2.getTransceivers(), [transceiver],
+ 'pc2.getTransceivers() equals [transceiver]');
+ assert_array_equals(pc2.getSenders(), [transceiver.sender],
+ 'pc2.getSenders() equals [transceiver.sender]');
+ assert_array_equals(pc2.getReceivers(), [transceiver.receiver],
+ 'pc2.getReceivers() equals [transceiver.receiver]');
+}, 'setRemoteDescription(offer): "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.transceiver.direction, 'recvonly');
+}, 'setRemoteDescription(offer): transceiver.direction is recvonly');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.transceiver.currentDirection, null);
+}, 'setRemoteDescription(offer): transceiver.currentDirection is null');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
+ assert_false(trackEvent.transceiver.stopped);
+}, 'setRemoteDescription(offer): transceiver.stopped is false');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ const transceiver = trackEvent.transceiver;
+ assert_equals(transceiver.currentDirection, null,
+ 'SRD(offer): transceiver.currentDirection is null');
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ assert_equals(transceiver.currentDirection, 'recvonly',
+ 'SLD(answer): transceiver.currentDirection is recvonly');
+}, 'setLocalDescription(answer): transceiver.currentDirection is recvonly');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
+ const pc2 = createPeerConnectionWithCleanup(t);
+ await exchangeOffer(pc1, pc2);
+ assert_equals(transceiver.currentDirection, null,
+ 'SLD(offer): transceiver.currentDirection is null');
+ await exchangeAnswer(pc1, pc2);
+ assert_equals(transceiver.currentDirection, 'sendonly',
+ 'SRD(answer): transceiver.currentDirection is sendonly');
+}, 'setLocalDescription(answer): transceiver.currentDirection is sendonly');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver(track);
+ assert_true(transceiver instanceof RTCRtpTransceiver);
+ assert_true(transceiver.sender instanceof RTCRtpSender);
+ assert_true(transceiver.receiver instanceof RTCRtpReceiver);
+ assert_equals(transceiver.sender.track, track);
+}, 'addTransceiver(track): creates a transceiver for the track');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver(track);
+ assert_array_equals(pc.getTransceivers(), [transceiver],
+ 'pc.getTransceivers() equals [transceiver]');
+ assert_array_equals(pc.getSenders(), [transceiver.sender],
+ 'pc.getSenders() equals [transceiver.sender]');
+ assert_array_equals(pc.getReceivers(), [transceiver.receiver],
+ 'pc.getReceivers() equals [transceiver.receiver]');
+}, 'addTransceiver(track): "transceiver == {sender,receiver}"');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver(track, {direction:'inactive'});
+ assert_equals(transceiver.direction, 'inactive');
+}, 'addTransceiver(track, init): initialize direction to inactive');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const otherPc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver(track, {
+ sendEncodings: [{active:false}]
+ });
+
+ // Negotiate parameters.
+ const offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ await otherPc.setRemoteDescription(offer);
+ const answer = await otherPc.createAnswer();
+ await otherPc.setLocalDescription(answer);
+ await pc.setRemoteDescription(answer);
+
+ const params = transceiver.sender.getParameters();
+ assert_false(params.encodings[0].active);
+}, 'addTransceiver(track, init): initialize sendEncodings[0].active to false');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ pc1.addTransceiver(track, {streams:[]});
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
+}, 'addTransceiver(0 streams): ontrack fires with no stream');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ const stream = new MediaStream();
+ pc1.addTransceiver(track, {streams:[stream]});
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
+ assert_equals(trackEvent.streams[0].id, stream.id,
+ 'trackEvent.streams[0].id == stream.id');
+}, 'addTransceiver(1 stream): ontrack fires with corresponding stream');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ const stream0 = new MediaStream();
+ const stream1 = new MediaStream();
+ pc1.addTransceiver(track, {streams:[stream0, stream1]});
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
+ assert_equals(trackEvent.streams[0].id, stream0.id,
+ 'trackEvent.streams[0].id == stream0.id');
+ assert_equals(trackEvent.streams[1].id, stream1.id,
+ 'trackEvent.streams[1].id == stream1.id');
+}, 'addTransceiver(2 streams): ontrack fires with corresponding two streams');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ pc1.addTrack(track);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 0, 'trackEvent.streams.length == 0');
+}, 'addTrack(0 streams): ontrack fires with no stream');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ const stream = new MediaStream();
+ pc1.addTrack(track, stream);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 1, 'trackEvent.streams.length == 1');
+ assert_equals(trackEvent.streams[0].id, stream.id,
+ 'trackEvent.streams[0].id == stream.id');
+}, 'addTrack(1 stream): ontrack fires with corresponding stream');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track] = await createTrackAndStreamWithCleanup(t);
+ const stream0 = new MediaStream();
+ const stream1 = new MediaStream();
+ pc1.addTrack(track, stream0, stream1);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ assert_equals(trackEvent.streams.length, 2, 'trackEvent.streams.length == 2');
+ assert_equals(trackEvent.streams[0].id, stream0.id,
+ 'trackEvent.streams[0].id == stream0.id');
+ assert_equals(trackEvent.streams[1].id, stream1.id,
+ 'trackEvent.streams[1].id == stream1.id');
+}, 'addTrack(2 streams): ontrack fires with corresponding two streams');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.direction, 'sendrecv');
+}, 'addTransceiver(\'audio\'): creates a transceiver with direction sendrecv');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.receiver.track.kind, 'audio');
+}, 'addTransceiver(\'audio\'): transceiver.receiver.track.kind == \'audio\'');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('video');
+ assert_equals(transceiver.receiver.track.kind, 'video');
+}, 'addTransceiver(\'video\'): transceiver.receiver.track.kind == \'video\'');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.sender.track, null);
+}, 'addTransceiver(\'audio\'): transceiver.sender.track == null');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.currentDirection, null);
+}, 'addTransceiver(\'audio\'): transceiver.currentDirection is null');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const transceiver = pc.addTransceiver('audio');
+ // `stopped` is non-standard. Move to external/wpt/webrtc/legacy/?
+ assert_false(transceiver.stopped);
+}, 'addTransceiver(\'audio\'): transceiver.stopped is false');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
+ const transceiver = pc.addTransceiver('audio');
+ const sender = pc.addTrack(track, stream);
+ assert_equals(sender, transceiver.sender, 'sender == transceiver.sender');
+ assert_equals(sender.track, track, 'sender.track == track');
+}, 'addTrack reuses reusable transceivers');
+
+promise_test(async t => {
+ const pc = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
+ const t1 = pc.addTransceiver('audio');
+ const t2 = pc.addTransceiver(track);
+ assert_not_equals(t2, t1, 't2 != t1');
+ assert_equals(t2.sender.track, track, 't2.sender.track == track');
+}, 'addTransceiver does not reuse reusable transceivers');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t);
+ const pc1Transceiver = findTransceiverForSender(pc1, pc1.addTrack(track, stream));
+ const pc2TrackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ const pc2Transceiver = pc2TrackEvent.transceiver;
+ assert_equals(pc2Transceiver.direction, 'recvonly',
+ 'pc2Transceiver.direction is recvonly after SRD(offer)');
+ const pc2Sender = pc2.addTrack(track, stream);
+ assert_equals(pc2Transceiver.sender, pc2Sender,
+ 'pc2Transceiver.sender == sender');
+ assert_equals(pc2Transceiver.direction, 'sendrecv',
+ 'pc2Transceiver.direction is sendrecv after addTrack()');
+ assert_equals(pc2Transceiver.currentDirection, null,
+ 'pc2Transceiver.currentDirection is null before answer');
+ const pc1TrackEvent = await exchangeAnswerAndListenToOntrack(t, pc1, pc2);
+ assert_equals(pc2Transceiver.currentDirection, 'sendrecv',
+ 'pc2Transceiver.currentDirection is sendrecv after SLD(answer)');
+ assert_equals(pc1TrackEvent.transceiver, pc1Transceiver,
+ 'Answer: pc1.ontrack fires with the existing transceiver.');
+ assert_equals(pc1Transceiver.currentDirection, 'sendrecv',
+ 'pc1Transceiver.currentDirection is sendrecv');
+ assert_equals(pc2.getTransceivers().length, 1,
+ 'pc2.getTransceivers().length == 1');
+ assert_equals(pc1.getTransceivers().length, 1,
+ 'pc1.getTransceivers().length == 1');
+}, 'Can setup two-way call using a single transceiver');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ const [track, stream] = await createTrackAndStreamWithCleanup(t, 'audio');
+ const transceiver = pc1.addTransceiver(track);
+ await exchangeOffer(pc1, pc2);
+ await exchangeAnswer(pc1, pc2);
+ assert_equals(transceiver.currentDirection, 'sendonly');
+ assert_false(transceiver.stopped);
+ pc1.close();
+ assert_equals(transceiver.currentDirection, 'stopped');
+ assert_true(transceiver.stopped);
+}, 'Closing the PC stops the transceivers');
+
+promise_test(async t => {
+ const pc1 = createPeerConnectionWithCleanup(t);
+ const pc1Sender = pc1.addTrack(... await createTrackAndStreamWithCleanup(t));
+ const localTransceiver = findTransceiverForSender(pc1, pc1Sender);
+ const pc2 = createPeerConnectionWithCleanup(t);
+ exchangeIceCandidates(pc1, pc2);
+
+ const e = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ await exchangeAnswer(pc1, pc2);
+ localTransceiver.direction = 'inactive';
+ await exchangeOfferAnswer(pc1, pc2);
+
+ localTransceiver.direction = 'sendrecv';
+ await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+}, 'Changing transceiver direction to \'sendrecv\' makes ontrack fire');
+
+// Regression test coverage for https://crbug.com/950280.
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const pc2Promise = pc2.createOffer()
+ .then((offer) => { return pc1.setRemoteDescription(offer); })
+ .then(() => { return pc1.createAnswer(); })
+ .then((answer) => { return pc1.setLocalDescription(answer); });
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const pc1Promise = pc1.createOffer()
+ .then(() => { pc1.addTrack(pc1.getReceivers()[0].track); });
+ await Promise.all([pc1Promise, pc2Promise]);
+ assert_equals(pc1.getSenders()[0].track, pc1.getReceivers()[0].track);
+}, 'transceiver.sender.track does not revert to an old state');
+
+// Regression test coverage for https://crbug.com/950280.
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const pc2Promise = pc2.createOffer()
+ .then((offer) => { return pc1.setRemoteDescription(offer); })
+ .then(() => { return pc1.createAnswer(); });
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ const pc1Promise = pc1.createOffer()
+ .then(() => { pc1.getTransceivers()[0].direction = 'inactive'; });
+ await Promise.all([pc1Promise, pc2Promise]);
+ assert_equals(pc1.getTransceivers()[0].direction, 'inactive');
+}, 'transceiver.direction does not revert to an old state');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection Video detector test</title>
+<body>
+ <p>The test passes if the video is being outputted .</p>
+</body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// This test verifies that the helper function "detectSignal" from
+// RTCPeerConnectionHelper, which is used to detect changes in a video
+// signal, performs properly for a range of "signal" values.
+
+// If it fails, it indicates that the video codec used in this particular
+// browser at this time doesn't reproduce the luma signal reliably enough
+// for this particular application, which may lead to other tests that
+// use the "detectSignal" helper failing without an obvious cause.
+
+// The most likely failure is timeout - which will happen if the
+// luma value detected doesn't settle within the margin of error before
+// the test times out.
+
+async function signalSettlementTime(t, v, sender, signal, backgroundTrack) {
+ const detectionStream = await getNoiseStream({video: {signal}});
+ const [detectionTrack] = detectionStream.getTracks();
+ try {
+ await sender.replaceTrack(detectionTrack);
+ const framesBefore = v.getVideoPlaybackQuality().totalVideoFrames;
+ await detectSignal(t, v, signal);
+ const framesAfter = v.getVideoPlaybackQuality().totalVideoFrames;
+ await sender.replaceTrack(backgroundTrack);
+ await detectSignal(t, v, 100);
+ return framesAfter - framesBefore;
+ } finally {
+ detectionTrack.stop();
+ }
+}
+
+promise_test(async t => {
+ const v = document.createElement('video');
+ v.autoplay = true;
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream1 = await getNoiseStream({video: {signal: 100}});
+ const [track1] = stream1.getTracks();
+ t.add_cleanup(() => track1.stop());
+
+ const sender = pc1.addTrack(track1);
+ const haveTrackEvent = new Promise(r => pc2.ontrack = r);
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ v.srcObject = new MediaStream([(await haveTrackEvent).track]);
+ await new Promise(r => v.onloadedmetadata = r);
+ // The basic signal is a track with signal 100. We replace this
+ // with tracks with signal from 0 to 255 and see if they are all
+ // reliably detected.
+ await detectSignal(t, v, 100);
+ // A few buffered frames are received with the old content, and a few
+ // frames may not have settled on exactly the right value. In testing,
+ // this test passes with maxFrames = 3; give a little more margin.
+ const maxFrames = 7;
+ // Test values 0 and 255
+ let maxCount = await signalSettlementTime(t, v, sender, 0, track1);
+ assert_less_than(maxCount, maxFrames,
+ 'Should get the black value within ' + maxFrames + ' frames');
+ maxCount = Math.max(
+ await signalSettlementTime(t, v, sender, 255, track1), maxCount);
+ assert_less_than(maxCount, maxFrames,
+ 'Should get the white value within ' + maxFrames + ' frames');
+ // Test a set of other values - far enough apart to make the test fast.
+ for (let signal = 2; signal <= 255; signal += 47) {
+ if (Math.abs(signal - 100) > 10) {
+ const count = await signalSettlementTime(t, v, sender, signal, track1);
+ maxCount = Math.max(count, maxCount);
+ assert_less_than(maxCount, 10,
+ 'Should get value ' + signal + ' within ' + maxFrames + ' frames');
+ }
+ }
+ assert_less_than(maxCount, 10, 'Should get the right value within 10 frames');
+}, 'Signal detector detects track change within reasonable time');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+
+test(() => {
+ init = {
+ address: "168.3.4.5",
+ port: 4711,
+ url: "turn:turn.example.org",
+ errorCode: 703,
+ errorText: "Test error"
+ };
+ event = new RTCPeerConnectionIceErrorEvent('type', init);
+ assert_equals(event.type, 'type');
+ assert_equals(event.address, '168.3.4.5');
+ assert_equals(event.port, 4711);
+ assert_equals(event.url, "turn:turn.example.org");
+ assert_equals(event.errorCode, 703);
+ assert_equals(event.errorText, "Test error");
+}, 'RTCPeerConnectionIceErrorEvent constructed from init parameters');
+
+</script>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<!--
+4.8.2 RTCPeerConnectionIceEvent
+
+ The icecandidate event of the RTCPeerConnection uses the RTCPeerConnectionIceEvent interface.
+
+-->
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+/*
+RTCPeerConnectionIceEvent
+
+[Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict)]
+
+interface RTCPeerConnectionIceEvent : Event {
+ readonly attribute RTCIceCandidate? candidate;
+ readonly attribute DOMString? url;
+};
+ */
+test(() => {
+ assert_throws_js(TypeError, () => {
+ new RTCPeerConnectionIceEvent();
+ });
+}, "RTCPeerConnectionIceEvent with no arguments throws TypeError");
+
+test(() => {
+ const event = new RTCPeerConnectionIceEvent("type", {
+ candidate: null
+ });
+ assert_equals(event.candidate, null);
+}, "RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: null }");
+
+test(() => {
+ const event = new RTCPeerConnectionIceEvent("type", {
+ candidate: undefined
+ });
+ assert_equals(event.candidate, null);
+}, "RTCPeerConnectionIceEvent.candidate is null when constructed with { candidate: undefined }");
+
+
+/*
+
+4.8.1 RTCIceCandidate Interface
+
+The RTCIceCandidate() constructor takes a dictionary argument, candidateInitDict,
+whose content is used to initialize the new RTCIceCandidate object. When run, if
+both the sdpMid and sdpMLineIndex dictionary members are null, throw a TypeError.
+*/
+const candidate = "";
+const sdpMid = "sdpMid";
+const sdpMLineIndex = 1;
+const usernameFragment = "";
+const url = "foo.bar";
+
+test(() => {
+ const iceCandidate = new RTCIceCandidate({ candidate, sdpMid, sdpMLineIndex, usernameFragment });
+ const event = new RTCPeerConnectionIceEvent("type", {
+ candidate: iceCandidate,
+ url,
+ });
+
+ assert_equals(event.candidate, iceCandidate);
+ assert_false(event.bubbles);
+ assert_false(event.cancelable);
+}, "RTCPeerConnectionIceEvent with RTCIceCandidate");
+
+test(() => {
+ const plain = { candidate, sdpMid, sdpMLineIndex, usernameFragment };
+ assert_throws_js(TypeError, () => new RTCPeerConnectionIceEvent("type", { candidate: plain }));
+}, "RTCPeerConnectionIceEvent with non RTCIceCandidate object throws");
+
+test(() => {
+ const event = new RTCPeerConnectionIceEvent("type", {
+ candidate: null,
+ bubbles: true,
+ cancelable: true,
+ });
+
+ assert_true(event.bubbles);
+ assert_true(event.cancelable);
+}, "RTCPeerConnectionIceEvent bubbles and cancelable");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpParameters codecs</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // doOfferAnswerExchange
+ // validateSenderRtpParameters
+
+ /*
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ Promise<void> setParameters(optional RTCRtpParameters parameters);
+ RTCRtpParameters getParameters();
+ };
+
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ dictionary RTCRtpCodecParameters {
+ [readonly]
+ unsigned short payloadType;
+
+ [readonly]
+ DOMString mimeType;
+
+ [readonly]
+ unsigned long clockRate;
+
+ [readonly]
+ unsigned short channels;
+
+ [readonly]
+ DOMString sdpFmtpLine;
+ };
+
+ getParameters
+ - The codecs sequence is populated based on the codecs that have been negotiated
+ for sending, and which the user agent is currently capable of sending.
+
+ If setParameters has removed or reordered codecs, getParameters MUST return
+ the shortened/reordered list. However, every time codecs are renegotiated by
+ a new offer/answer exchange, the list of codecs MUST be restored to the full
+ negotiated set, in the priority order indicated by the remote description,
+ in effect discarding the effects of setParameters.
+
+ codecs
+ - When using the setParameters method, the codecs sequence from the corresponding
+ call to getParameters can be reordered and entries can be removed, but entries
+ cannot be added, and the RTCRtpCodecParameters dictionary members cannot be modified.
+ */
+
+ // Get the first codec from param.codecs.
+ // Assert that param.codecs has at least one element
+ function getFirstCodec(param) {
+ const { codecs } = param;
+ assert_greater_than(codecs.length, 0);
+ return codecs[0];
+ }
+
+ /*
+ 5.2. setParameters
+ 7. If parameters.encodings.length is different from N, or if any parameter
+ in the parameters argument, marked as a Read-only parameter, has a value
+ that is different from the corresponding parameter value returned from
+ sender.getParameters(), abort these steps and return a promise rejected
+ with a newly created InvalidModificationError. Note that this also applies
+ to transactionId.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const codec = getFirstCodec(param);
+
+ if(codec.payloadType === undefined) {
+ codec.payloadType = 8;
+ } else {
+ codec.payloadType += 1;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with codec.payloadType modified should reject with InvalidModificationError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const codec = getFirstCodec(param);
+
+ if(codec.mimeType === undefined) {
+ codec.mimeType = 'audio/piedpiper';
+ } else {
+ codec.mimeType = `${codec.mimeType}-modified`;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with codec.mimeType modified should reject with InvalidModificationError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const codec = getFirstCodec(param);
+
+ if(codec.clockRate === undefined) {
+ codec.clockRate = 8000;
+ } else {
+ codec.clockRate += 1;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with codec.clockRate modified should reject with InvalidModificationError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const codec = getFirstCodec(param);
+
+ if(codec.channels === undefined) {
+ codec.channels = 6;
+ } else {
+ codec.channels += 1;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with codec.channels modified should reject with InvalidModificationError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const codec = getFirstCodec(param);
+
+ if(codec.sdpFmtpLine === undefined) {
+ codec.sdpFmtpLine = 'a=fmtp:98 0-15';
+ } else {
+ codec.sdpFmtpLine = `${codec.sdpFmtpLine};foo=1`;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with codec.sdpFmtpLine modified should reject with InvalidModificationError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const { codecs } = param;
+
+ codecs.push({
+ payloadType: 2,
+ mimeType: 'audio/piedpiper',
+ clockRate: 1000,
+ channels: 2
+ });
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, 'setParameters() with new codecs inserted should reject with InvalidModificationError');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpParameters encodings</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // validateSenderRtpParameters
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+ partial interface RTCPeerConnection {
+ RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ optional RTCRtpTransceiverInit init);
+ ...
+ };
+
+ dictionary RTCRtpTransceiverInit {
+ RTCRtpTransceiverDirection direction = "sendrecv";
+ sequence<MediaStream> streams;
+ sequence<RTCRtpEncodingParameters> sendEncodings;
+ };
+
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ Promise<void> setParameters(optional RTCRtpParameters parameters);
+ RTCRtpParameters getParameters();
+ };
+
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ dictionary RTCRtpEncodingParameters {
+ boolean active;
+ unsigned long maxBitrate;
+
+ [readonly]
+ DOMString rid;
+
+ double scaleResolutionDownBy;
+ };
+
+ getParameters
+ - encodings is set to the value of the [[send encodings]] internal slot.
+ */
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video');
+
+ const param = transceiver.sender.getParameters();
+ assert_equals(param.encodings.length, 1);
+ // Do not call this in every test; it does not make sense to disable all of
+ // the tests below for an implementation that is missing support for
+ // fields that are not related to the test.
+ validateSenderRtpParameters(param);
+ }, `getParameters should return RTCRtpEncodingParameters with all required fields`);
+
+ /*
+ 5.1. addTransceiver
+ 7. Create an RTCRtpSender with track, streams and sendEncodings and let sender
+ be the result.
+
+ 5.2. create an RTCRtpSender
+ 5. Let sender have a [[send encodings]] internal slot, representing a list
+ of RTCRtpEncodingParameters dictionaries.
+ 6. If sendEncodings is given as input to this algorithm, and is non-empty,
+ set the [[send encodings]] slot to sendEncodings.
+
+ Otherwise, set it to a list containing a single RTCRtpEncodingParameters
+ with active set to true.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.active, true);
+ assert_not_own_property(encoding, "maxBitrate");
+ assert_not_own_property(encoding, "rid");
+ assert_not_own_property(encoding, "scaleResolutionDownBy");
+ // We do not check props from extension specifications here; those checks
+ // need to go in a test-case for that extension specification.
+ }, 'addTransceiver(audio) with undefined sendEncodings should have default encoding parameter with active set to true');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video');
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.active, true);
+ // spec says to return an encoding without a scaleResolutionDownBy value
+ // when addTransceiver does not pass any encodings, however spec also says
+ // to throw if setParameters is missing a scaleResolutionDownBy. One of
+ // these two requirements needs to be removed, but it is unclear right now
+ // which will be removed. For now, allow scaleResolutionDownBy, but don't
+ // require it.
+ // https://github.com/w3c/webrtc-pc/issues/2730
+ assert_not_own_property(encoding, "maxBitrate");
+ assert_not_own_property(encoding, "rid");
+ assert_equals(encoding.scaleResolutionDownBy, undefined);
+ // We do not check props from extension specifications here; those checks
+ // need to go in a test-case for that extension specification.
+ }, 'addTransceiver(video) with undefined sendEncodings should have default encoding parameter with active set to true and scaleResolutionDownBy set to 1');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio', { sendEncodings: [] });
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.active, true);
+ assert_not_own_property(encoding, "maxBitrate");
+ assert_not_own_property(encoding, "rid");
+ assert_not_own_property(encoding, "scaleResolutionDownBy");
+ // We do not check props from extension specifications here; those checks
+ // need to go in a test-case for that extension specification.
+ }, 'addTransceiver(audio) with empty list sendEncodings should have default encoding parameter with active set to true');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video', { sendEncodings: [] });
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.active, true);
+ assert_not_own_property(encoding, "maxBitrate");
+ assert_not_own_property(encoding, "rid");
+ assert_equals(encoding.scaleResolutionDownBy, undefined);
+ // We do not check props from extension specifications here; those checks
+ // need to go in a test-case for that extension specification.
+ }, 'addTransceiver(video) with empty list sendEncodings should have default encoding parameter with active set to true and scaleResolutionDownBy set to 1');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar", scaleResolutionDownBy: 3.0}]});
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 2);
+ assert_equals(encodings[0].scaleResolutionDownBy, undefined);
+ assert_equals(encodings[1].scaleResolutionDownBy, 3.0);
+ }, `addTransceiver(video) should auto-set scaleResolutionDownBy to 1 when some encodings have it, but not all`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 2);
+ assert_equals(encodings[0].scaleResolutionDownBy, undefined);
+ assert_equals(encodings[1].scaleResolutionDownBy, undefined);
+ }, `addTransceiver should auto-set scaleResolutionDownBy to powers of 2 (descending) when absent`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const sendEncodings = [];
+ for (let i = 0; i < 1000; i++) {
+ sendEncodings.push({rid: i});
+ }
+ const transceiver = pc.addTransceiver('video', {sendEncodings});
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_less_than(encodings.length, 1000, `1000 encodings is clearly too many`);
+ }, `addTransceiver with a ridiculous number of encodings should truncate the list`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
+
+ const param = transceiver.sender.getParameters();
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+ assert_not_own_property(encodings[0], "maxBitrate");
+ assert_not_own_property(encodings[0], "rid");
+ assert_not_own_property(encodings[0], "scaleResolutionDownBy");
+ // We do not check props from extension specifications here; those checks
+ // need to go in a test-case for that extension specification.
+ }, `addTransceiver(audio) with multiple encodings should result in one encoding with no properties other than active`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {sender} = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo", scaleResolutionDownBy: 2.0}]});
+ const {encodings} = sender.getParameters();
+ assert_equals(encodings.length, 1);
+ assert_not_own_property(encodings[0], "scaleResolutionDownBy");
+ }, `addTransceiver(audio) should remove valid scaleResolutionDownBy`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {sender} = pc.addTransceiver('audio', {sendEncodings: [{rid: "foo", scaleResolutionDownBy: -1.0}]});
+ const {encodings} = sender.getParameters();
+ assert_equals(encodings.length, 1);
+ assert_not_own_property(encodings[0], "scaleResolutionDownBy");
+ }, `addTransceiver(audio) should remove invalid scaleResolutionDownBy`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {sender} = pc.addTransceiver('audio');
+ let params = sender.getParameters();
+ assert_equals(params.encodings.length, 1);
+ params.encodings[0].scaleResolutionDownBy = 2;
+ await sender.setParameters(params);
+ const {encodings} = sender.getParameters();
+ assert_equals(encodings.length, 1);
+ assert_not_own_property(encodings[0], "scaleResolutionDownBy");
+ }, `setParameters with scaleResolutionDownBy on an audio sender should succeed, but remove the scaleResolutionDownBy`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {sender} = pc.addTransceiver('audio');
+ let params = sender.getParameters();
+ assert_equals(params.encodings.length, 1);
+ params.encodings[0].scaleResolutionDownBy = -1;
+ await sender.setParameters(params);
+ const {encodings} = sender.getParameters();
+ assert_equals(encodings.length, 1);
+ assert_not_own_property(encodings[0], "scaleResolutionDownBy");
+ }, `setParameters with an invalid scaleResolutionDownBy on an audio sender should succeed, but remove the scaleResolutionDownBy`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo"}, {rid: "foo"}] }));
+ }, 'addTransceiver with duplicate rid and multiple encodings throws TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo"}, {}] }));
+ }, 'addTransceiver with missing rid and multiple encodings throws TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: ""}] }));
+ }, 'addTransceiver with empty rid throws TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "!?"}] }));
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "(âŊ°âĄÂ°)âŊïļĩ âŧââŧ"}] }));
+ // RFC 8851 says '-' and '_' are allowed, but RFC 8852 says they are not.
+ // RFC 8852 needs to be adhered to, otherwise we can't put the rid in RTP
+ // https://github.com/w3c/webrtc-pc/issues/2732
+ // https://www.rfc-editor.org/errata/eid7132
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo-bar"}] }));
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: "foo_bar"}] }));
+ }, 'addTransceiver with invalid rid characters throws TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ // https://github.com/w3c/webrtc-pc/issues/2732
+ assert_throws_js(TypeError, () => pc.addTransceiver('video', { sendEncodings: [{rid: 'a'.repeat(256)}] }));
+ }, 'addTransceiver with rid longer than 255 characters throws TypeError');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: -1}] }));
+ assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: 0}] }));
+ assert_throws_js(RangeError, () => pc.addTransceiver('video', { sendEncodings: [{scaleResolutionDownBy: 0.5}] }));
+ }, `addTransceiver with scaleResolutionDownBy < 1 throws RangeError`);
+
+ /*
+ 5.2. create an RTCRtpSender
+ To create an RTCRtpSender with a MediaStreamTrack , track, a list of MediaStream
+ objects, streams, and optionally a list of RTCRtpEncodingParameters objects,
+ sendEncodings, run the following steps:
+ 5. Let sender have a [[send encodings]] internal slot, representing a list
+ of RTCRtpEncodingParameters dictionaries.
+
+ 6. If sendEncodings is given as input to this algorithm, and is non-empty,
+ set the [[send encodings]] slot to sendEncodings.
+
+ 5.2. getParameters
+ - encodings is set to the value of the [[send encodings]] internal slot.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video', {
+ sendEncodings: [{
+ active: false,
+ maxBitrate: 8,
+ rid: 'foo'
+ }]
+ });
+
+ const param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.active, false);
+ assert_equals(encoding.maxBitrate, 8);
+ assert_not_own_property(encoding, "rid", "rid should be removed with a single encoding");
+
+ }, `sender.getParameters() should return sendEncodings set by addTransceiver()`);
+
+ /*
+ 5.2. setParameters
+ 3. Let N be the number of RTCRtpEncodingParameters stored in sender's internal
+ [[send encodings]] slot.
+ 7. If parameters.encodings.length is different from N, or if any parameter
+ in the parameters argument, marked as a Read-only parameter, has a value
+ that is different from the corresponding parameter value returned from
+ sender.getParameters(), abort these steps and return a promise rejected
+ with a newly created InvalidModificationError. Note that this also applies
+ to transactionId.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video');
+
+ const param = sender.getParameters();
+
+ const { encodings } = param;
+ assert_equals(encodings.length, 1);
+
+ // While {} is valid RTCRtpEncodingParameters because all fields are
+ // optional, it is still invalid to be missing a rid when there are multiple
+ // encodings. Only trigger one kind of error here.
+ encodings.push({ rid: "foo" });
+ assert_equals(param.encodings.length, 2);
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `sender.setParameters() with added encodings should reject with InvalidModificationError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
+
+ const param = sender.getParameters();
+
+ const { encodings } = param;
+ assert_equals(encodings.length, 2);
+
+ encodings.pop();
+ assert_equals(param.encodings.length, 1);
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `sender.setParameters() with removed encodings should reject with InvalidModificationError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video', {sendEncodings: [{rid: "foo"}, {rid: "bar"}]});
+
+ const param = sender.getParameters();
+
+ const { encodings } = param;
+ assert_equals(encodings.length, 2);
+ encodings.push(encodings.shift());
+ assert_equals(param.encodings.length, 2);
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `sender.setParameters() with reordered encodings should reject with InvalidModificationError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video');
+
+ const param = sender.getParameters();
+
+ delete param.encodings;
+
+ return promise_rejects_js(t, TypeError,
+ sender.setParameters(param));
+ }, `sender.setParameters() with encodings unset should reject with TypeError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video', {
+ sendEncodings: [{ rid: 'foo' }, { rid: 'baz' }],
+ });
+
+ const param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ assert_equals(encoding.rid, 'foo');
+
+ encoding.rid = 'bar';
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `setParameters() with modified encoding.rid field should reject with InvalidModificationError`);
+
+ /*
+ 5.2. setParameters
+ 8. If the scaleResolutionDownBy parameter in the parameters argument has a
+ value less than 1.0, abort these steps and return a promise rejected with
+ a newly created RangeError.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video');
+
+ const param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ encoding.scaleResolutionDownBy = 0.5;
+ return promise_rejects_js(t, RangeError, sender.setParameters(param));
+ encoding.scaleResolutionDownBy = 0;
+ return promise_rejects_js(t, RangeError, sender.setParameters(param));
+ encoding.scaleResolutionDownBy = -1;
+ return promise_rejects_js(t, RangeError, sender.setParameters(param));
+ }, `setParameters() with encoding.scaleResolutionDownBy field set to less than 1.0 should reject with RangeError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video');
+
+ let param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ delete encoding.scaleResolutionDownBy;
+ await sender.setParameters(param);
+ param = sender.getParameters();
+ assert_equals(param.encodings[0].scaleResolutionDownBy, undefined);
+ }, `setParameters() with missing encoding.scaleResolutionDownBy field should succeed, and set the value back to 1`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('video');
+
+ const param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ encoding.scaleResolutionDownBy = 1.5;
+ return sender.setParameters(param)
+ .then(() => {
+ const param = sender.getParameters();
+ const encoding = param.encodings[0];
+
+ assert_approx_equals(encoding.scaleResolutionDownBy, 1.5, 0.01);
+ });
+ }, `setParameters() with encoding.scaleResolutionDownBy field set to greater than 1.0 should succeed`);
+
+ test_modified_encoding('video', 'active', false, true,
+ 'setParameters() with encoding.active false->true should succeed (video)');
+
+ test_modified_encoding('video', 'active', true, false,
+ 'setParameters() with encoding.active true->false should succeed (video)');
+
+ test_modified_encoding('video', 'maxBitrate', 10000, 20000,
+ 'setParameters() with modified encoding.maxBitrate should succeed (video)');
+
+ test_modified_encoding('audio', 'active', false, true,
+ 'setParameters() with encoding.active false->true should succeed (audio)');
+
+ test_modified_encoding('audio', 'active', true, false,
+ 'setParameters() with encoding.active true->false should succeed (audio)');
+
+ test_modified_encoding('audio', 'maxBitrate', 10000, 20000,
+ 'setParameters() with modified encoding.maxBitrate should succeed (audio)');
+
+ test_modified_encoding('video', 'scaleResolutionDownBy', 2, 4,
+ 'setParameters() with modified encoding.scaleResolutionDownBy should succeed');
+
+</script>
\ No newline at end of file
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpParameters headerExtensions</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // validateSenderRtpParameters
+
+ /*
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ Promise<void> setParameters(optional RTCRtpParameters parameters);
+ RTCRtpParameters getParameters();
+ };
+
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ dictionary RTCRtpHeaderExtensionParameters {
+ [readonly]
+ DOMString uri;
+
+ [readonly]
+ unsigned short id;
+
+ [readonly]
+ boolean encrypted;
+ };
+
+ getParameters
+ - The headerExtensions sequence is populated based on the header extensions
+ that have been negotiated for sending.
+ */
+
+ /*
+ 5.2. setParameters
+ 7. If parameters.encodings.length is different from N, or if any parameter
+ in the parameters argument, marked as a Read-only parameter, has a value
+ that is different from the corresponding parameter value returned from
+ sender.getParameters(), abort these steps and return a promise rejected
+ with a newly created InvalidModificationError. Note that this also applies
+ to transactionId.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ param.headerExtensions = [{
+ uri: 'non-existent.example.org',
+ id: 404,
+ encrypted: false
+ }];
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `setParameters() with modified headerExtensions should reject with InvalidModificationError`);
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpParameters rtcp</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // validateSenderRtpParameters
+
+ /*
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ Promise<void> setParameters(optional RTCRtpParameters parameters);
+ RTCRtpParameters getParameters();
+ };
+
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ dictionary RTCRtcpParameters {
+ [readonly]
+ DOMString cname;
+
+ [readonly]
+ boolean reducedSize;
+ };
+
+ getParameters
+ - rtcp.cname is set to the CNAME of the associated RTCPeerConnection.
+
+ rtcp.reducedSize is set to true if reduced-size RTCP has been negotiated for
+ sending, and false otherwise.
+ */
+
+ /*
+ 5.2. setParameters
+ 7. If parameters.encodings.length is different from N, or if any parameter
+ in the parameters argument, marked as a Read-only parameter, has a value
+ that is different from the corresponding parameter value returned from
+ sender.getParameters(), abort these steps and return a promise rejected
+ with a newly created InvalidModificationError. Note that this also applies
+ to transactionId.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const { rtcp } = param;
+
+ if(rtcp === undefined) {
+ param.rtcp = { cname: 'foo' };
+
+ } else if(rtcp.cname === undefined) {
+ rtcp.cname = 'foo';
+
+ } else {
+ rtcp.cname = `${rtcp.cname}-modified`;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `setParameters() with modified rtcp.cname should reject with InvalidModificationError`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const { rtcp } = param;
+
+ if(rtcp === undefined) {
+ param.rtcp = { reducedSize: true };
+
+ } else if(rtcp.reducedSize === undefined) {
+ rtcp.reducedSize = true;
+
+ } else {
+ rtcp.reducedSize = !rtcp.reducedSize;
+ }
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `setParameters() with modified rtcp.reducedSize should reject with InvalidModificationError`);
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpParameters transactionId</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // doOfferAnswerExchange
+ // validateSenderRtpParameters
+
+ /*
+ 5.1. RTCPeerConnection Interface Extensions
+ partial interface RTCPeerConnection {
+ RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
+ optional RTCRtpTransceiverInit init);
+ ...
+ };
+
+ dictionary RTCRtpTransceiverInit {
+ RTCRtpTransceiverDirection direction = "sendrecv";
+ sequence<MediaStream> streams;
+ sequence<RTCRtpEncodingParameters> sendEncodings;
+ };
+
+ addTransceiver
+ 2. If the dictionary argument is present, and it has a sendEncodings member,
+ let sendEncodings be that list of RTCRtpEncodingParameters objects, or an
+ empty list otherwise.
+ 7. Create an RTCRtpSender with track, streams and sendEncodings and let
+ sender be the result.
+
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ Promise<void> setParameters(optional RTCRtpParameters parameters);
+ RTCRtpParameters getParameters();
+ };
+
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ getParameters
+ - transactionId is set to a new unique identifier, used to match this
+ getParameters call to a setParameters call that may occur later.
+ */
+
+ /*
+ 5.2. getParameters
+ - transactionId is set to a new unique identifier, used to match this
+ getParameters call to a setParameters call that may occur later.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param1 = sender.getParameters();
+ const param2 = sender.getParameters();
+
+ validateSenderRtpParameters(param1);
+ validateSenderRtpParameters(param2);
+
+ assert_not_equals(param1.transactionId, param2.transactionId);
+ }, `sender.getParameters() should return different transaction IDs for each call`);
+
+ /*
+ 5.2. setParameters
+ 7. If parameters.encodings.length is different from N, or if any parameter
+ in the parameters argument, marked as a Read-only parameter, has a value
+ that is different from the corresponding parameter value returned from
+ sender.getParameters(), abort these steps and return a promise rejected
+ with a newly created InvalidModificationError. Note that this also applies
+ to transactionId.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ const { transactionId } = param;
+ param.transactionId = `${transactionId}-modified`;
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param));
+ }, `sender.setParameters() with transaction ID different from last getParameters() should reject with InvalidModificationError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ param.transactionId = undefined;
+
+ return promise_rejects_js(t, TypeError,
+ sender.setParameters(param));
+ }, `sender.setParameters() with transaction ID unset should reject with TypeError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param = sender.getParameters();
+ validateSenderRtpParameters(param);
+
+ return sender.setParameters(param)
+ .then(() =>
+ promise_rejects_dom(t, 'InvalidStateError',
+ sender.setParameters(param)));
+ }, `setParameters() twice with the same parameters should reject with InvalidStateError`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const { sender } = pc.addTransceiver('audio');
+ await doOfferAnswerExchange(t, pc);
+
+ const param1 = sender.getParameters();
+ const param2 = sender.getParameters();
+
+ validateSenderRtpParameters(param1);
+ validateSenderRtpParameters(param2);
+
+ assert_not_equals(param1.transactionId, param2.transactionId);
+
+ return promise_rejects_dom(t, 'InvalidModificationError',
+ sender.setParameters(param1));
+ }, `setParameters() with parameters older than last getParameters() should reject with InvalidModificationError`);
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpReceiver.getCapabilities</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpCapabilities-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 RTCRtpCapabilities-helper.js:
+ // validateRtpCapabilities
+
+ /*
+ 5.3. RTCRtpReceiver Interface
+ interface RTCRtpReceiver {
+ ...
+ static RTCRtpCapabilities getCapabilities(DOMString kind);
+ };
+ */
+ test(() => {
+ const capabilities = RTCRtpReceiver.getCapabilities('audio');
+ validateRtpCapabilities(capabilities);
+ }, `RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary`);
+
+ test(() => {
+ const capabilities = RTCRtpReceiver.getCapabilities('video');
+ validateRtpCapabilities(capabilities);
+ }, `RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary`);
+
+ test(() => {
+ const capabilities = RTCRtpReceiver.getCapabilities('dummy');
+ assert_equals(capabilities, null);
+ }, `RTCRtpSender.getCapabilities('dummy') should return null`);
+
+ </script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpReceiver.prototype.getContributingSources</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+async function connectAndExpectNoCsrcs(t, kind) {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({[kind]:true});
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+ pc1.addTrack(track, stream);
+
+ exchangeIceCandidates(pc1, pc2);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ await exchangeAnswer(pc1, pc2);
+
+ assert_array_equals(trackEvent.receiver.getContributingSources(), []);
+}
+
+promise_test(async t => {
+ await connectAndExpectNoCsrcs(t, 'audio');
+}, '[audio] getContributingSources() returns an empty list in loopback call');
+
+promise_test(async t => {
+ await connectAndExpectNoCsrcs(t, 'video');
+}, '[video] getContributingSources() returns an empty list in loopback call');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpReceiver.prototype.getParameters</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpParameters-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 RTCRtpParameters-helper.js:
+ // validateReceiverRtpParameters
+
+ /*
+ Validates the RTCRtpParameters returned from RTCRtpReceiver.prototype.getParameters
+
+ 5.3. RTCRtpReceiver Interface
+ getParameters
+ When getParameters is called, the RTCRtpParameters dictionary is constructed
+ as follows:
+
+ - The headerExtensions sequence is populated based on the header extensions that
+ the receiver is currently prepared to receive.
+
+ - The codecs sequence is populated based on the codecs that the receiver is currently
+ prepared to receive.
+
+ - rtcp.reducedSize is set to true if the receiver is currently prepared to receive
+ reduced-size RTCP packets, and false otherwise. rtcp.cname is left undefined.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('audio');
+ const callee = await doOfferAnswerExchange(t, pc);
+ const param = callee.getTransceivers()[0].receiver.getParameters();
+ validateReceiverRtpParameters(param);
+
+ assert_greater_than(param.headerExtensions.length, 0);
+ assert_greater_than(param.codecs.length, 0);
+ }, 'getParameters() with audio receiver');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver('video');
+ const callee = await doOfferAnswerExchange(t, pc);
+ const param = callee.getTransceivers()[0].receiver.getParameters();
+ validateReceiverRtpParameters(param);
+
+ assert_greater_than(param.headerExtensions.length, 0);
+ assert_greater_than(param.codecs.length, 0);
+ }, 'getParameters() with video receiver');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title></title>
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // A generous testing duration that will not time out on bots.
+ const kEncodeDurationMs = 10000;
+
+ // The crash this test aims to repro was easy to reproduce using a normal
+ // getUserMedia() track when running the browser normally, e.g. by navigating
+ // to https://jsfiddle.net/henbos/fc7gk3ve/11/. But for some reason, the fake
+ // tracks returned by getUserMedia() when inside this testing environment had
+ // a much harder time with reproducibility.
+ //
+ // By creating a high FPS canvas capture track we are able to repro reliably
+ // in this WPT environment as well.
+ function whiteNoise(width, height) {
+ const canvas =
+ Object.assign(document.createElement('canvas'), {width, height});
+ const ctx = canvas.getContext('2d');
+ ctx.fillRect(0, 0, width, height);
+ const p = ctx.getImageData(0, 0, width, height);
+ requestAnimationFrame(function draw () {
+ for (let i = 0; i < p.data.length; i++) {
+ const color = Math.random() * 255;
+ p.data[i++] = color;
+ p.data[i++] = color;
+ p.data[i++] = color;
+ }
+ ctx.putImageData(p, 0, 0);
+ requestAnimationFrame(draw);
+ });
+ return canvas.captureStream();
+ }
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = whiteNoise(640, 480);
+ const [track] = stream.getTracks();
+ const t1 = pc1.addTransceiver("video", {direction:"sendonly"});
+ const t2 = pc1.addTransceiver("video", {direction:"sendonly"});
+ await t1.sender.replaceTrack(track);
+ await t2.sender.replaceTrack(track);
+
+ exchangeIceCandidates(pc1, pc2);
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // In Chromium, each sender instantiates a VideoStreamEncoder during
+ // negotiation. This test reproduces https://crbug.com/webrtc/11485 where a
+ // race causes a crash when multiple VideoStreamEncoders are encoding the
+ // same MediaStreamTrack.
+ await new Promise(resolve => t.step_timeout(resolve, kEncodeDurationMs));
+ }, "Two RTCRtpSenders encoding the same track");
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpSender.getCapabilities</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCRtpCapabilities-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 RTCRtpCapabilities-helper.js:
+ // validateRtpCapabilities
+
+ /*
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ ...
+ static RTCRtpCapabilities getCapabilities(DOMString kind);
+ };
+
+ getCapabilities
+ The getCapabilities() method returns the most optimist view on the capabilities
+ of the system for sending media of the given kind. It does not reserve any
+ resources, ports, or other state but is meant to provide a way to discover
+ the types of capabilities of the browser including which codecs may be supported.
+ */
+ test(() => {
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ validateRtpCapabilities(capabilities);
+ }, `RTCRtpSender.getCapabilities('audio') should return RTCRtpCapabilities dictionary`);
+
+ test(() => {
+ const capabilities = RTCRtpSender.getCapabilities('video');
+ validateRtpCapabilities(capabilities);
+ }, `RTCRtpSender.getCapabilities('video') should return RTCRtpCapabilities dictionary`);
+
+ test(() => {
+ const capabilities = RTCRtpSender.getCapabilities('dummy');
+ assert_equals(capabilities, null);
+ }, `RTCRtpSender.getCapabilities('dummy') should return null`);
+
+ </script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCRtpSender.prototype.replaceTrack</title>
+<body>
+ <p>The test passes if the video is being outputted .</p>
+</body>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/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
+
+ /*
+ 5.2. RTCRtpSender Interface
+ interface RTCRtpSender {
+ readonly attribute MediaStreamTrack? track;
+ Promise<void> replaceTrack(MediaStreamTrack? withTrack);
+ ...
+ };
+
+ replaceTrack
+ Attempts to replace the track being sent with another track provided
+ (or with a null track), without renegotiation.
+ */
+
+ /*
+ 5.2. replaceTrack
+ 4. If connection's [[isClosed]] slot is true, return a promise rejected
+ with a newly created InvalidStateError and abort these steps.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const transceiver = pc.addTransceiver('audio');
+ const { sender } = transceiver;
+ pc.close();
+
+ return promise_rejects_dom(t, 'InvalidStateError',
+ sender.replaceTrack(track));
+ }, 'Calling replaceTrack on closed connection should reject with InvalidStateError');
+
+ /*
+ 5.2. replaceTrack
+ 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.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const transceiver = pc.addTransceiver('audio');
+ const { sender } = transceiver;
+ assert_equals(sender.track, null);
+
+ return sender.replaceTrack(track)
+ .then(() => {
+ assert_equals(sender.track, track);
+ });
+ }, 'Calling replaceTrack on sender with null track and not set to session description should resolve with sender.track set to given track');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ const [track1] = stream1.getTracks();
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ const [track2] = stream2.getTracks();
+
+ const transceiver = pc.addTransceiver(track1);
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track1);
+
+ return sender.replaceTrack(track2)
+ .then(() => {
+ assert_equals(sender.track, track2);
+ });
+ }, 'Calling replaceTrack on sender not set to session description should resolve with sender.track set to given track');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+
+ return sender.replaceTrack(null)
+ .then(() => {
+ assert_equals(sender.track, null);
+ });
+ }, 'Calling replaceTrack(null) on sender not set to session description should resolve with sender.track set to null');
+
+ /*
+ 5.2. replaceTrack
+ 10. Run the following steps in parallel:
+ 1. Determine if negotiation is needed to transmit withTrack in place
+ of the sender's existing track.
+
+ Negotiation is not needed if withTrack is null.
+
+ 3. Queue a task that runs the following steps:
+ 2. Set sender's track attribute to withTrack.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const transceiver = pc.addTransceiver(track);
+ const { sender } = transceiver;
+
+ assert_equals(sender.track, track);
+
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => sender.replaceTrack(null))
+ .then(() => {
+ assert_equals(sender.track, null);
+ });
+ }, 'Calling replaceTrack(null) on sender set to session description should resolve with sender.track set to null');
+
+ /*
+ 5.2. replaceTrack
+ 10. Run the following steps in parallel:
+ 1. Determine if negotiation is needed to transmit withTrack in place
+ of the sender's existing track.
+
+ Negotiation is not needed if the sender's existing track is
+ ended (which appears as though the track was muted).
+
+ 3. Queue a task that runs the following steps:
+ 2. Set sender's track attribute to withTrack.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ const [track1] = stream1.getTracks();
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ const [track2] = stream1.getTracks();
+
+ const transceiver = pc.addTransceiver(track1);
+ const { sender } = transceiver;
+ assert_equals(sender.track, track1);
+
+ track1.stop();
+
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => sender.replaceTrack(track2))
+ .then(() => {
+ assert_equals(sender.track, track2);
+ });
+ }, 'Calling replaceTrack on sender with stopped track and and set to session description should resolve with sender.track set to given track');
+
+ /*
+ 5.2. replaceTrack
+ 10. Run the following steps in parallel:
+ 1. Determine if negotiation is needed to transmit withTrack in place
+ of the sender's existing track.
+
+ (tracks generated with default parameters *should* be similar
+ enough to not require re-negotiation)
+
+ 3. Queue a task that runs the following steps:
+ 2. Set sender's track attribute to withTrack.
+ */
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ const [track1] = stream1.getTracks();
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ const [track2] = stream1.getTracks();
+
+ const transceiver = pc.addTransceiver(track1);
+ const { sender } = transceiver;
+ assert_equals(sender.track, track1);
+
+ return pc.createOffer()
+ .then(offer => pc.setLocalDescription(offer))
+ .then(() => sender.replaceTrack(track2))
+ .then(() => {
+ assert_equals(sender.track, track2);
+ });
+ }, 'Calling replaceTrack on sender with similar track and and set to session description should resolve with sender.track set to new track');
+
+ /*
+ TODO
+ 5.2. replaceTrack
+ To avoid track identifiers changing on the remote receiving end when
+ a track is replaced, the sender must retain the original track
+ identifier and stream associations and use these in subsequent
+ negotiations.
+
+ Non-Testable
+ 5.2. replaceTrack
+ 10. Run the following steps in parallel:
+ 1. Determine if negotiation is needed to transmit withTrack in place
+ of the sender's existing track.
+
+ Ignore which MediaStream the track resides in and the id attribute
+ of the track in this determination.
+
+ If negotiation is needed, then reject p with a newly created
+ InvalidModificationError and abort these steps.
+
+ 2. If withTrack is null, have the sender stop sending, without
+ 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.
+ */
+
+promise_test(async t => {
+ const v = document.createElement('video');
+ v.autoplay = true;
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const stream1 = await getNoiseStream({video: {signal: 20}});
+ t.add_cleanup(() => stream1.getTracks().forEach(track => track.stop()));
+ const [track1] = stream1.getTracks();
+ const stream2 = await getNoiseStream({video: {signal: 250}});
+ t.add_cleanup(() => stream2.getTracks().forEach(track => track.stop()));
+ const [track2] = stream2.getTracks();
+ const sender = pc1.addTrack(track1);
+ pc2.ontrack = (e) => {
+ v.srcObject = new MediaStream([e.track]);
+ };
+ const metadataToBeLoaded = new Promise((resolve) => {
+ v.addEventListener('loadedmetadata', () => {
+ resolve();
+ });
+ });
+ exchangeIceCandidates(pc1, pc2);
+ exchangeOfferAnswer(pc1, pc2);
+ await metadataToBeLoaded;
+ await detectSignal(t, v, 20);
+ await sender.replaceTrack(track2);
+ await detectSignal(t, v, 250);
+}, 'ReplaceTrack transmits the new track not the old track');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpSender.prototype.setParameters</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ /*
+ 5.2. setParameters
+ 6. If transceiver.stopped is true, abort these steps and return a promise
+ rejected with a newly created InvalidStateError.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const { sender } = transceiver;
+
+ const param = sender.getParameters();
+ transceiver.stop();
+
+ return promise_rejects_dom(t, 'InvalidStateError',
+ sender.setParameters(param));
+ }, `setParameters() when transceiver is stopped should reject with InvalidStateError`);
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpSender.prototype.setStreams</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const sender = caller.addTrack(track);
+ const stream1 = new MediaStream();
+ const stream2 = new MediaStream();
+ sender.setStreams(stream1, stream2);
+
+ const offer = await caller.createOffer();
+ callee.setRemoteDescription(offer);
+ return new Promise(resolve => callee.ontrack = t.step_func(event =>{
+ assert_equals(event.streams.length, 2);
+ const calleeStreamIds = event.streams.map(s => s.id);
+ assert_in_array(stream1.id, calleeStreamIds);
+ assert_in_array(stream2.id, calleeStreamIds);
+ resolve();
+ }));
+}, 'setStreams causes streams to be reported via ontrack on callee');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+
+ const sender = caller.addTrack(track);
+ sender.setStreams(stream);
+
+ const offer = await caller.createOffer();
+ callee.setRemoteDescription(offer);
+ return new Promise(resolve => callee.ontrack = t.step_func(event =>{
+ assert_equals(event.streams.length, 1);
+ assert_equals(stream.id, event.streams[0].id);
+ assert_equals(track.id, event.track.id);
+ assert_equals(event.streams[0].getTracks()[0], event.track);
+ resolve();
+ }));
+}, 'setStreams can be used to reconstruct a stream with a track on the remote side');
+
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ callee.ontrack = t.unreached_func();
+ const transceiver = caller.addTransceiver('audio', {direction: 'inactive'});
+ await exchangeOfferAnswer(caller, callee);
+
+ const stream1 = new MediaStream();
+ const stream2 = new MediaStream();
+ transceiver.direction = 'sendrecv';
+ transceiver.sender.setStreams(stream1, stream2);
+
+ const offer = await caller.createOffer();
+ callee.setRemoteDescription(offer);
+ return new Promise(resolve => callee.ontrack = t.step_func(event =>{
+ assert_equals(event.streams.length, 2);
+ const calleeStreamIds = event.streams.map(s => s.id);
+ assert_in_array(stream1.id, calleeStreamIds);
+ assert_in_array(stream2.id, calleeStreamIds);
+ assert_in_array(event.track, event.streams[0].getTracks());
+ assert_in_array(event.track, event.streams[1].getTracks());
+ resolve();
+ }));
+}, 'Adding streams and changing direction causes new streams to be reported via ontrack on callee');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+
+ const stream1 = new MediaStream();
+ const stream2 = new MediaStream();
+ let calleeTrack = null;
+ callee.ontrack = t.step_func(event => {
+ assert_equals(event.streams.length, 0);
+ calleeTrack = event.track;
+ });
+ const transceiver = caller.addTransceiver('audio', {direction: 'sendrecv'});
+ await exchangeOfferAnswer(caller, callee);
+ assert_true(calleeTrack instanceof MediaStreamTrack);
+
+ transceiver.sender.setStreams(stream1, stream2);
+ const offer = await caller.createOffer();
+ callee.setRemoteDescription(offer);
+ return new Promise(resolve => callee.ontrack = t.step_func(event =>{
+ assert_equals(event.streams.length, 2);
+ const calleeStreamIds = event.streams.map(s => s.id);
+ assert_in_array(stream1.id, calleeStreamIds);
+ assert_in_array(stream2.id, calleeStreamIds);
+ assert_in_array(event.track, event.streams[0].getTracks());
+ assert_in_array(event.track, event.streams[1].getTracks());
+ assert_equals(event.track, calleeTrack);
+ resolve();
+ }));
+}, 'Adding streams to an active transceiver causes new streams to be reported via ontrack on callee');
+
+test(t => {
+ const pc = new RTCPeerConnection();
+ const stream1 = new MediaStream();
+ const stream2 = new MediaStream();
+ const transceiver = pc.addTransceiver('audio');
+
+ pc.close();
+ assert_throws_dom('InvalidStateError', () => transceiver.sender.setStreams(stream1, stream2));
+}, 'setStreams() fires InvalidStateError on a closed peer connection.');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCRtpSender.transport</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/dictionary-helper.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Spec link: http://w3c.github.io/webrtc-pc/#dom-rtcrtpsender-transport
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = caller.addTrack(track);
+ assert_equals(sender.transport, null);
+ }, 'RTCRtpSender.transport is null when unconnected');
+
+ // Test for the simple/happy path of connecting a single track
+ promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track] = stream.getTracks();
+ const sender = caller.addTrack(track);
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ exchangeIceCandidates(caller, callee);
+ await exchangeOfferAndListenToOntrack(t, caller, callee);
+ assert_not_equals(sender.transport, null);
+ const [transceiver] = caller.getTransceivers();
+ assert_equals(transceiver.sender.transport,
+ transceiver.receiver.transport);
+ assert_not_equals(sender.transport.iceTransport, null);
+ }, 'RTCRtpSender/receiver.transport has a value when connected');
+
+ // Test with multiple tracks, and checking details of when things show up
+ // for different bundle policies.
+ for (let bundle_policy of ['balanced', 'max-bundle', 'max-compat']) {
+ promise_test(async t => {
+ const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
+ t.add_cleanup(() => caller.close());
+ const stream = await getNoiseStream(
+ {audio: true, video:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track1, track2] = stream.getTracks();
+ const sender1 = caller.addTrack(track1);
+ const sender2 = caller.addTrack(track2);
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ exchangeIceCandidates(caller, callee);
+ const offer = await caller.createOffer();
+ assert_equals(sender1.transport, null);
+ assert_equals(sender2.transport, null);
+ await caller.setLocalDescription(offer);
+ assert_not_equals(sender1.transport, null);
+ assert_not_equals(sender2.transport, null);
+ const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
+ assert_equals(sender1.transport, caller_transceiver1.sender.transport);
+ if (bundle_policy == 'max-bundle') {
+ assert_equals(caller_transceiver1.sender.transport,
+ caller_transceiver2.sender.transport);
+ } else {
+ assert_not_equals(caller_transceiver1.sender.transport,
+ caller_transceiver2.sender.transport);
+ }
+ await callee.setRemoteDescription(offer);
+ const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
+ // According to spec, setRemoteDescription only updates the transports
+ // if the remote description is an answer.
+ assert_equals(callee_transceiver1.receiver.transport, null);
+ assert_equals(callee_transceiver2.receiver.transport, null);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ assert_not_equals(callee_transceiver1.receiver.transport, null);
+ assert_not_equals(callee_transceiver2.receiver.transport, null);
+ // At this point, bundle should have kicked in.
+ assert_equals(callee_transceiver1.receiver.transport,
+ callee_transceiver2.receiver.transport);
+ await caller.setRemoteDescription(answer);
+ assert_equals(caller_transceiver1.receiver.transport,
+ caller_transceiver2.receiver.transport);
+ }, 'RTCRtpSender/receiver.transport at the right time, with bundle policy ' + bundle_policy);
+
+ // Do the same test again, with DataChannel in the mix.
+ promise_test(async t => {
+ const caller = new RTCPeerConnection({bundlePolicy: bundle_policy});
+ t.add_cleanup(() => caller.close());
+ const stream = await getNoiseStream(
+ {audio: true, video:true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const [track1, track2] = stream.getTracks();
+ const sender1 = caller.addTrack(track1);
+ const sender2 = caller.addTrack(track2);
+ caller.createDataChannel('datachannel');
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ exchangeIceCandidates(caller, callee);
+ const offer = await caller.createOffer();
+ assert_equals(sender1.transport, null);
+ assert_equals(sender2.transport, null);
+ if (caller.sctp) {
+ assert_equals(caller.sctp.transport, null);
+ }
+ await caller.setLocalDescription(offer);
+ assert_not_equals(sender1.transport, null);
+ assert_not_equals(sender2.transport, null);
+ assert_not_equals(caller.sctp.transport, null);
+ const [caller_transceiver1, caller_transceiver2] = caller.getTransceivers();
+ assert_equals(sender1.transport, caller_transceiver1.sender.transport);
+ if (bundle_policy == 'max-bundle') {
+ assert_equals(caller_transceiver1.sender.transport,
+ caller_transceiver2.sender.transport);
+ assert_equals(caller_transceiver1.sender.transport,
+ caller.sctp.transport);
+ } else {
+ assert_not_equals(caller_transceiver1.sender.transport,
+ caller_transceiver2.sender.transport);
+ assert_not_equals(caller_transceiver1.sender.transport,
+ caller.sctp.transport);
+ }
+ await callee.setRemoteDescription(offer);
+ const [callee_transceiver1, callee_transceiver2] = callee.getTransceivers();
+ // According to spec, setRemoteDescription only updates the transports
+ // if the remote description is an answer.
+ assert_equals(callee_transceiver1.receiver.transport, null);
+ assert_equals(callee_transceiver2.receiver.transport, null);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ assert_not_equals(callee_transceiver1.receiver.transport, null);
+ assert_not_equals(callee_transceiver2.receiver.transport, null);
+ assert_not_equals(callee.sctp.transport, null);
+ // At this point, bundle should have kicked in.
+ assert_equals(callee_transceiver1.receiver.transport,
+ callee_transceiver2.receiver.transport);
+ assert_equals(callee_transceiver1.receiver.transport,
+ callee.sctp.transport,
+ 'Callee SCTP transport does not match:');
+ await caller.setRemoteDescription(answer);
+ assert_equals(caller_transceiver1.receiver.transport,
+ caller_transceiver2.receiver.transport);
+ assert_equals(caller_transceiver1.receiver.transport,
+ caller.sctp.transport,
+ 'Caller SCTP transport does not match:');
+ }, 'RTCRtpSender/receiver/SCTP transport at the right time, with bundle policy ' + bundle_policy);
+ }
+ </script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpSender</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const t1 = pc.addTransceiver("audio");
+ const t2 = pc.addTransceiver("video");
+
+ assert_not_equals(t1.sender.dtmf, null);
+ assert_equals(t2.sender.dtmf, null);
+}, "Video sender @dtmf is null");
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpTransceiver.prototype.direction</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://rawgit.com/w3c/webrtc-pc/8495678808d126d8bc764bf944996f32981fa6fd/webrtc.html
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // generateAnswer
+
+ /*
+ 5.4. RTCRtpTransceiver Interface
+ interface RTCRtpTransceiver {
+ attribute RTCRtpTransceiverDirection direction;
+ readonly attribute RTCRtpTransceiverDirection? currentDirection;
+ ...
+ };
+ */
+
+ /*
+ 5.4. direction
+ 7. Set transceiver's [[Direction]] slot to newDirection.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_equals(transceiver.currentDirection, null);
+
+ transceiver.direction = 'recvonly';
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, null,
+ 'Expect transceiver.currentDirection to not change');
+
+ }, 'setting direction should change transceiver.direction');
+
+ /*
+ 5.4. direction
+ 3. If newDirection is equal to transceiver's [[Direction]] slot, abort
+ these steps.
+ */
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio', { direction: 'sendonly' });
+ assert_equals(transceiver.direction, 'sendonly');
+ transceiver.direction = 'sendonly';
+ assert_equals(transceiver.direction, 'sendonly');
+
+ }, 'setting direction with same direction should have no effect');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio', { direction: 'recvonly' });
+ assert_equals(transceiver.direction, 'recvonly');
+ assert_equals(transceiver.currentDirection, null);
+
+ return pc.createOffer()
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer)))
+ .then(answer => pc.setRemoteDescription(answer))
+ .then(() => {
+ assert_equals(transceiver.currentDirection, 'inactive');
+ transceiver.direction = 'sendrecv';
+ assert_equals(transceiver.direction, 'sendrecv');
+ assert_equals(transceiver.currentDirection, 'inactive');
+ });
+ }, 'setting direction should change transceiver.direction independent of transceiver.currentDirection');
+
+ /*
+ TODO
+ An update of directionality does not take effect immediately. Instead, future calls
+ to createOffer and createAnswer mark the corresponding media description as
+ sendrecv, sendonly, recvonly or inactive as defined in [JSEP] (section 5.2.2.
+ and section 5.3.2.).
+
+ Tested in RTCPeerConnection-onnegotiationneeded.html
+ 5.4. direction
+ 6. Update the negotiation-needed flag for connection.
+
+ Coverage Report
+ Tested 6
+ Not Tested 1
+ Untestable 0
+ Total 7
+ */
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpTransceiver.prototype.setCodecPreferences</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="./third_party/sdp/sdp.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ /*
+ 5.4. RTCRtpTransceiver Interface
+ interface RTCRtpTransceiver {
+ ...
+ void setCodecPreferences(sequence<RTCRtpCodecCapability> codecs);
+ };
+
+ setCodecPreferences
+ - Setting codecs to an empty sequence resets codec preferences to any
+ default value.
+
+ - The codecs sequence passed into setCodecPreferences can only contain
+ codecs that are returned by RTCRtpSender.getCapabilities(kind) or
+ RTCRtpReceiver.getCapabilities(kind), where kind is the kind of the
+ RTCRtpTransceiver on which the method is called. Additionally, the
+ RTCRtpCodecParameters dictionary members cannot be modified. If
+ codecs does not fulfill these requirements, the user agent MUST throw
+ an InvalidModificationError.
+ */
+ /*
+ * Chromium note: this requires build bots with H264 support. See
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
+ * for details on how to enable support.
+ */
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ transceiver.setCodecPreferences(capabilities.codecs);
+ }, `setCodecPreferences() on audio transceiver with codecs returned from RTCRtpSender.getCapabilities('audio') should succeed`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video');
+ const capabilities = RTCRtpReceiver.getCapabilities('video');
+ transceiver.setCodecPreferences(capabilities.codecs);
+ }, `setCodecPreferences() on video transceiver with codecs returned from RTCRtpReceiver.getCapabilities('video') should succeed`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities1 = RTCRtpSender.getCapabilities('audio');
+ const capabilities2 = RTCRtpReceiver.getCapabilities('audio');
+ transceiver.setCodecPreferences([...capabilities1.codecs, ... capabilities2.codecs]);
+ }, `setCodecPreferences() with both sender receiver codecs combined should succeed`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ transceiver.setCodecPreferences([]);
+ }, `setCodecPreferences([]) should succeed`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ const { codecs } = capabilities;
+
+ if(codecs.length >= 2) {
+ const tmp = codecs[0];
+ codecs[0] = codecs[1];
+ codecs[1] = tmp;
+ }
+
+ transceiver.setCodecPreferences(codecs);
+ }, `setCodecPreferences() with reordered codecs should succeed`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('video');
+ const capabilities = RTCRtpSender.getCapabilities('video');
+ const { codecs } = capabilities;
+ // This test verifies that the mandatory VP8 codec is present
+ // and can be set.
+ let tried = false;
+ codecs.forEach(codec => {
+ if (codec.mimeType.toLowerCase() === 'video/vp8') {
+ transceiver.setCodecPreferences([codecs[0]]);
+ tried = true;
+ }
+ });
+ assert_true(tried, 'VP8 video codec was found and tried');
+ }, `setCodecPreferences() with only VP8 should succeed`);
+
+ test(() => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('video');
+ const capabilities = RTCRtpSender.getCapabilities('video');
+ const { codecs } = capabilities;
+ // This test verifies that the mandatory H264 codec is present
+ // and can be set.
+ let tried = false;
+ codecs.forEach(codec => {
+ if (codec.mimeType.toLowerCase() === 'video/h264') {
+ transceiver.setCodecPreferences([codecs[0]]);
+ tried = true;
+ }
+ });
+ assert_true(tried, 'H264 video codec was found and tried');
+ }, `setCodecPreferences() with only H264 should succeed`);
+
+ async function getRTPMapLinesWithCodecAsFirst(firstCodec)
+ {
+ const capabilities = RTCRtpSender.getCapabilities('video').codecs;
+ capabilities.forEach((codec, idx) => {
+ if (codec.mimeType === firstCodec) {
+ capabilities.splice(idx, 1);
+ capabilities.unshift(codec);
+ }
+ });
+
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('video');
+ transceiver.setCodecPreferences(capabilities);
+ const offer = await pc.createOffer();
+
+ return offer.sdp.split('\r\n').filter(line => line.indexOf("a=rtpmap") === 0);
+ }
+
+ promise_test(async () => {
+ const lines = await getRTPMapLinesWithCodecAsFirst('video/VP8');
+
+ assert_greater_than(lines.length, 1);
+ assert_true(lines[0].indexOf("VP8") !== -1, "VP8 should be the first codec");
+ }, `setCodecPreferences() should allow setting VP8 as first codec`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('video');
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(capabilities.codecs));
+ }, `setCodecPreferences() on audio transceiver with codecs returned from getCapabilities('video') should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const codecs = [{
+ mimeType: 'data',
+ clockRate: 2000,
+ channels: 2,
+ sdpFmtpLine: '0-15'
+ }];
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with user defined codec with invalid mimeType should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const codecs = [{
+ mimeType: 'audio/piepiper',
+ clockRate: 2000,
+ channels: 2,
+ sdpFmtpLine: '0-15'
+ }];
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with user defined codec should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ const codecs = [
+ ...capabilities.codecs,
+ {
+ mimeType: 'audio/piepiper',
+ clockRate: 2000,
+ channels: 2,
+ sdpFmtpLine: '0-15'
+ }];
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with user defined codec together with codecs returned from getCapabilities() should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ const codecs = [capabilities.codecs[0]];
+ codecs[0].clockRate = codecs[0].clockRate / 2;
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with modified codec clock rate should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ const codecs = [capabilities.codecs[0]];
+ codecs[0].channels = codecs[0].channels + 11;
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with modified codec channel count should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+ const codecs = [capabilities.codecs[0]];
+ codecs[0].sdpFmtpLine = "modifiedparameter=1";
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with modified codec parameters should throw InvalidModificationError`);
+
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const capabilities = RTCRtpSender.getCapabilities('audio');
+
+ const { codecs } = capabilities;
+ assert_greater_than(codecs.length, 0,
+ 'Expect at least one codec available');
+
+ const [ codec ] = codecs;
+ const { channels=2 } = codec;
+ codec.channels = channels+1;
+
+ assert_throws_dom('InvalidModificationError', () => transceiver.setCodecPreferences(codecs));
+ }, `setCodecPreferences() with modified codecs returned from getCapabilities() should throw InvalidModificationError`);
+
+ promise_test(async (t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const transceiver = pc.addTransceiver('audio');
+ const {codecs} = RTCRtpSender.getCapabilities('audio');
+ // Reorder codecs, put PCMU/PCMA first.
+ let firstCodec;
+ let i;
+ for (i = 0; i < codecs.length; i++) {
+ const codec = codecs[i];
+ if (codec.mimeType === 'audio/PCMU' || codec.mimeType === 'audio/PCMA') {
+ codecs.splice(i, 1);
+ codecs.unshift(codec);
+ firstCodec = codec.mimeType.substr(6);
+ break;
+ }
+ }
+ assert_not_equals(firstCodec, undefined, 'PCMU or PCMA codec not found');
+ transceiver.setCodecPreferences(codecs);
+
+ const offer = await pc.createOffer();
+ const mediaSection = SDPUtils.getMediaSections(offer.sdp)[0];
+ const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
+ assert_equals(rtpParameters.codecs[0].name, firstCodec);
+ }, `setCodecPreferences() modifies the order of audio codecs in createOffer`);
+
+ </script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpTransceiver.prototype.stop</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+// FIXME: Add a test adding a transceiver, stopping it and trying to create an empty offer.
+
+promise_test(async (t)=> {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ pc1.addTransceiver("audio", { direction: "sendonly" });
+ pc1.addTransceiver("video");
+ pc1.getTransceivers()[0].stop();
+
+ const offer = await pc1.createOffer();
+
+ assert_false(offer.sdp.includes("m=audio"), "offer should not contain an audio m-section");
+ assert_true(offer.sdp.includes("m=video"), "offer should contain a video m-section");
+}, "A transceiver added and stopped before the initial offer generation should not trigger an offer m-section generation");
+
+promise_test(async (t)=> {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ pc1.addTransceiver("audio", { direction: "sendonly" });
+ pc1.addTransceiver("video");
+ assert_equals(null, pc1.getTransceivers()[1].receiver.transport);
+
+ pc1.getTransceivers()[1].stop();
+ assert_equals(pc1.getTransceivers()[1].receiver.transport, null);
+}, "A transceiver added and stopped should not crash when getting receiver's transport");
+
+promise_test(async (t)=> {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+
+ await exchangeOfferAnswer(pc1, pc2);
+
+ pc1.addTransceiver("video");
+
+ pc1.getTransceivers()[0].stop();
+ pc1.getTransceivers()[1].stop();
+
+ const offer = await pc1.createOffer();
+
+ assert_true(offer.sdp.includes("m=audio"), "offer should contain an audio m-section");
+ assert_true(offer.sdp.includes("m=audio 0"), "The audio m-section should be rejected");
+
+ assert_false(offer.sdp.includes("m=video"), "offer should not contain a video m-section");
+}, "During renegotiation, adding and stopping a transceiver should not trigger a renegotiated offer m-section generation");
+
+promise_test(async (t)=> {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+
+ await exchangeOfferAnswer(pc1, pc2);
+
+ pc1.getTransceivers()[0].direction = "sendonly";
+ pc1.getTransceivers()[0].stop();
+
+ const offer = await pc1.createOffer();
+
+ assert_true(offer.sdp.includes("a=inactive"), "The audio m-section should be inactive");
+}, "A stopped sendonly transceiver should generate an inactive m-section in the offer");
+
+promise_test(async (t)=> {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+
+ await exchangeOfferAnswer(pc1, pc2);
+
+ pc1.getTransceivers()[0].direction = "inactive";
+ pc1.getTransceivers()[0].stop();
+
+ const offer = await pc1.createOffer();
+
+ assert_true(offer.sdp.includes("a=inactive"), "The audio m-section should be inactive");
+}, "A stopped inactive transceiver should generate an inactive m-section in the offer");
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+ await exchangeOfferAnswer(pc1, pc2);
+ pc1.getTransceivers()[0].stop();
+ await exchangeOfferAnswer(pc1, pc2);
+ await pc1.setLocalDescription(await pc1.createOffer());
+}, 'If a transceiver is stopped locally, setting a locally generated answer should still work');
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+ await exchangeOfferAnswer(pc1, pc2);
+ pc2.getTransceivers()[0].stop();
+ await exchangeOfferAnswer(pc2, pc1);
+ await pc1.setLocalDescription(await pc1.createOffer());
+}, 'If a transceiver is stopped remotely, setting a locally generated answer should still work');
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+ await exchangeOfferAnswer(pc1, pc2);
+ assert_equals(pc1.getTransceivers().length, 1);
+ assert_equals(pc2.getTransceivers().length, 1);
+ pc1.getTransceivers()[0].stop();
+ await exchangeOfferAnswer(pc1, pc2);
+ assert_equals(pc1.getTransceivers().length, 0);
+ assert_equals(pc2.getTransceivers().length, 0);
+ assert_equals(pc1.getSenders().length, 0, 'caller senders');
+ assert_equals(pc1.getReceivers().length, 0, 'caller receivers');
+ assert_equals(pc2.getSenders().length, 0, 'callee senders');
+ assert_equals(pc2.getReceivers().length, 0, 'callee receivers');
+}, 'If a transceiver is stopped, transceivers, senders and receivers should disappear after offer/answer');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+['audio', 'video'].forEach((kind) => {
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver(kind);
+ const trackEnded = new Promise(
+ r => { transceiver.receiver.track.onended = () => { r(); } });
+ assert_equals(transceiver.receiver.track.readyState, 'live');
+ transceiver.stop();
+ // Stopping triggers ending the track, but this happens asynchronously.
+ assert_equals(transceiver.receiver.track.readyState, 'live');
+ await trackEnded;
+ assert_equals(transceiver.receiver.track.readyState, 'ended');
+ }, `[${kind}] Locally stopping a transceiver ends the track`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const pc1Transceiver = pc1.addTransceiver(kind);
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+ const [pc2Transceiver] = pc2.getTransceivers();
+
+ pc1Transceiver.stop();
+
+ await pc1.setLocalDescription();
+ assert_equals(pc2Transceiver.receiver.track.readyState, 'live');
+ // Applying the remote offer immediately ends the track, we don't need to
+ // create or apply an answer.
+ await pc2.setRemoteDescription(pc1.localDescription);
+ assert_equals(pc2Transceiver.receiver.track.readyState, 'ended');
+ }, `[${kind}] Remotely stopping a transceiver ends the track`);
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const transceiver = pc.addTransceiver(kind);
+
+ // Rollback does not end the track, because the transceiver is not removed.
+ await pc.setLocalDescription();
+ await pc.setLocalDescription({type:'rollback'});
+ assert_equals(transceiver.receiver.track.readyState, 'live');
+ }, `[${kind}] Rollback when transceiver is not removed does not end track`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const pc1Transceiver = pc1.addTransceiver(kind);
+
+ // Start negotiation, causing a transceiver to be created.
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ const [pc2Transceiver] = pc2.getTransceivers();
+
+ // Rollback such that the transceiver is removed.
+ await pc2.setLocalDescription({type:'rollback'});
+ assert_equals(pc2.getTransceivers().length, 0);
+ assert_equals(pc2Transceiver.receiver.track.readyState, 'ended');
+ }, `[${kind}] Rollback when removing transceiver does end the track`);
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ const [track] = stream.getTracks();
+
+ pc1.addTrack(track);
+ pc2.addTrack(track);
+ const transceiver = pc2.getTransceivers()[0];
+
+ const ontrackEvent = new Promise(r => {
+ pc2.ontrack = e => r(e.track);
+ });
+
+ // Simulate glare: both peer connections set local offers.
+ await pc1.setLocalDescription();
+ await pc2.setLocalDescription();
+ // Set remote offer, which implicitly rolls back the local offer. Because
+ // `transceiver` is an addTrack-transceiver, it should get repurposed.
+ await pc2.setRemoteDescription(pc1.localDescription);
+ assert_equals(transceiver.receiver.track.readyState, 'live');
+ // Sanity check: the track should still be live when ontrack fires.
+ assert_equals((await ontrackEvent).readyState, 'live');
+ }, `[${kind}] Glare when transceiver is not removed does not end track`);
+});
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCRtpTransceiver</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ const checkThrows = async (func, exceptionName, description) => {
+ try {
+ await func();
+ assert_true(false, description + " throws " + exceptionName);
+ } catch (e) {
+ assert_equals(e.name, exceptionName, description + " throws " + exceptionName);
+ }
+ };
+
+ const stopTracks = (...streams) => {
+ streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
+ };
+
+ const collectEvents = (target, name, check) => {
+ const events = [];
+ const handler = e => {
+ check(e);
+ events.push(e);
+ };
+
+ target.addEventListener(name, handler);
+
+ const finishCollecting = () => {
+ target.removeEventListener(name, handler);
+ return events;
+ };
+
+ return {finish: finishCollecting};
+ };
+
+ const collectAddTrackEvents = stream => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(stream.getTracks().includes(e.track),
+ "track in addtrack event is in the stream");
+ };
+ return collectEvents(stream, "addtrack", checkEvent);
+ };
+
+ const collectRemoveTrackEvents = stream => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(!stream.getTracks().includes(e.track),
+ "track in removetrack event is not in the stream");
+ };
+ return collectEvents(stream, "removetrack", checkEvent);
+ };
+
+ const collectTrackEvents = pc => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(e.receiver instanceof RTCRtpReceiver, "Receiver is set on event");
+ assert_true(e.transceiver instanceof RTCRtpTransceiver, "Transceiver is set on event");
+ assert_true(Array.isArray(e.streams), "Streams is set on event");
+ e.streams.forEach(stream => {
+ assert_true(stream.getTracks().includes(e.track),
+ "Each stream in event contains the track");
+ });
+ assert_equals(e.receiver, e.transceiver.receiver,
+ "Receiver belongs to transceiver");
+ assert_equals(e.track, e.receiver.track,
+ "Track belongs to receiver");
+ };
+
+ return collectEvents(pc, "track", checkEvent);
+ };
+
+ const setRemoteDescriptionReturnTrackEvents = async (pc, desc) => {
+ const trackEventCollector = collectTrackEvents(pc);
+ await pc.setRemoteDescription(desc);
+ return trackEventCollector.finish();
+ };
+
+ const offerAnswer = async (offerer, answerer) => {
+ const offer = await offerer.createOffer();
+ await answerer.setRemoteDescription(offer);
+ await offerer.setLocalDescription(offer);
+ const answer = await answerer.createAnswer();
+ await offerer.setRemoteDescription(answer);
+ await answerer.setLocalDescription(answer);
+ };
+
+ const trickle = (t, pc1, pc2) => {
+ pc1.onicecandidate = t.step_func(async e => {
+ try {
+ await pc2.addIceCandidate(e.candidate);
+ } catch (e) {
+ assert_true(false, "addIceCandidate threw error: " + e.name);
+ }
+ });
+ };
+
+ const iceConnected = pc => {
+ return new Promise((resolve, reject) => {
+ const iceCheck = () => {
+ if (pc.iceConnectionState == "connected") {
+ assert_true(true, "ICE connected");
+ resolve();
+ }
+
+ if (pc.iceConnectionState == "failed") {
+ assert_true(false, "ICE failed");
+ reject();
+ }
+ };
+
+ iceCheck();
+ pc.oniceconnectionstatechange = iceCheck;
+ });
+ };
+
+ const negotiationNeeded = pc => {
+ return new Promise(resolve => pc.onnegotiationneeded = resolve);
+ };
+
+ const countEvents = (target, name) => {
+ const result = {count: 0};
+ target.addEventListener(name, e => result.count++);
+ return result;
+ };
+
+ const gotMuteEvent = async track => {
+ await new Promise(r => track.addEventListener("mute", r, {once: true}));
+
+ assert_true(track.muted, "track should be muted after onmute");
+ };
+
+ const gotUnmuteEvent = async track => {
+ await new Promise(r => track.addEventListener("unmute", r, {once: true}));
+
+ assert_true(!track.muted, "track should not be muted after onunmute");
+ };
+
+ // comparable() - produces copy of object that is JSON comparable.
+ // o = original object (required)
+ // t = template of what to examine. Useful if o is non-enumerable (optional)
+
+ const comparable = (o, t = o) => {
+ if (typeof o != 'object' || !o) {
+ return o;
+ }
+ if (Array.isArray(t) && Array.isArray(o)) {
+ return o.map((n, i) => comparable(n, t[i]));
+ }
+ return Object.keys(t).sort()
+ .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
+ };
+
+ const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
+
+ const hasProps = (observed, expected) => {
+ const observable = comparable(observed, expected);
+ assert_equals(stripKeyQuotes(JSON.stringify(observable)),
+ stripKeyQuotes(JSON.stringify(comparable(expected))));
+ };
+
+ const hasPropsAndUniqueMids = (observed, expected) => {
+ hasProps(observed, expected);
+
+ const mids = [];
+ observed.forEach((transceiver, i) => {
+ if (!("mid" in expected[i])) {
+ assert_not_equals(transceiver.mid, null);
+ assert_equals(typeof transceiver.mid, "string");
+ }
+ if (transceiver.mid) {
+ assert_false(mids.includes(transceiver.mid), "mid must be unique");
+ mids.push(transceiver.mid);
+ }
+ });
+ };
+
+ const checkAddTransceiverNoTrack = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ hasProps(pc.getTransceivers(), []);
+
+ pc.addTransceiver("audio");
+ pc.addTransceiver("video");
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio", readyState: "live", muted: true}},
+ sender: {track: null},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ },
+ {
+ receiver: {track: {kind: "video", readyState: "live", muted: true}},
+ sender: {track: null},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverWithTrack = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+
+ pc.addTransceiver(audio);
+ pc.addTransceiver(video);
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: audio},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ },
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: video},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverWithAddTrack = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+
+ pc.addTrack(audio, stream);
+ pc.addTrack(video, stream);
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: audio},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ },
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: video},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverWithDirection = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver("audio", {direction: "recvonly"});
+ pc.addTransceiver("video", {direction: "recvonly"});
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ mid: null,
+ currentDirection: null,
+ },
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: null},
+ direction: "recvonly",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverWithSetRemoteOfferSending = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTransceiver(track, {streams: [stream]});
+
+ const offer = await pc1.createOffer();
+
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverWithSetRemoteOfferNoSend = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTransceiver(track);
+ pc1.getTransceivers()[0].direction = "recvonly";
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents, []);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ // rtcweb-jsep says this is recvonly, w3c-webrtc does not...
+ direction: "recvonly",
+ currentDirection: null,
+ }
+ ]);
+ };
+
+ const checkAddTransceiverBadKind = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ try {
+ pc.addTransceiver("foo");
+ assert_true(false, 'addTransceiver("foo") throws');
+ }
+ catch (e) {
+ if (e instanceof TypeError) {
+ assert_true(true, 'addTransceiver("foo") throws a TypeError');
+ } else {
+ assert_true(false, 'addTransceiver("foo") throws a TypeError');
+ }
+ }
+
+ hasProps(pc.getTransceivers(), []);
+ };
+
+ const checkMsidNoTrackId = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ // Remove track-id from msid
+ // Fixate stream-id so that error message is consistent.
+ offer.sdp = offer.sdp.replace(/(a=msid:[^ \t]+).*\r\n/g,
+ "a=msid:fake-stream-id\r\n");
+ await pc2.setRemoteDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ };
+
+ const checkNoMidOffer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+
+ // Remove mid attr
+ offer.sdp = offer.sdp.replace("a=mid:", "a=unknownattr:");
+ offer.sdp = offer.sdp.replace("a=group:", "a=unknownattr:");
+ await pc2.setRemoteDescription(offer);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ currentDirection: null,
+ }
+ ]);
+
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ };
+
+ const checkNoMidAnswer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: {kind: "audio"}},
+ direction: "sendrecv",
+ currentDirection: null,
+ }
+ ]);
+
+ const lastMid = pc1.getTransceivers()[0].mid;
+
+ let answer = await pc2.createAnswer();
+ // Remove mid attr
+ answer.sdp = answer.sdp.replace("a=mid:", "a=unknownattr:");
+ // Remove group attr also
+ answer.sdp = answer.sdp.replace("a=group:", "a=unknownattr:");
+ await pc1.setRemoteDescription(answer);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: {kind: "audio"}},
+ direction: "sendrecv",
+ currentDirection: "sendonly",
+ mid: lastMid
+ }
+ ]);
+
+ const reoffer = await pc1.createOffer();
+ await pc1.setLocalDescription(reoffer);
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: {kind: "audio"}},
+ direction: "sendrecv",
+ currentDirection: "sendonly",
+ mid: lastMid
+ }
+ ]);
+ };
+
+ const checkAddTransceiverNoTrackDoesntPair = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTransceiver("audio");
+ pc2.addTransceiver("audio");
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[1].receiver.track,
+ streams: []
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {mid: null}, // no addTrack magic, doesn't auto-pair
+ {} // Created by SRD
+ ]);
+ };
+
+ const checkAddTransceiverWithTrackDoesntPair = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc2.addTransceiver(track);
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[1].receiver.track,
+ streams: []
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {mid: null, sender: {track}},
+ {sender: {track: null}} // Created by SRD
+ ]);
+ };
+
+ const checkAddTransceiverThenReplaceTrackDoesntPair = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+ pc2.addTransceiver("audio");
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ await pc2.getTransceivers()[0].sender.replaceTrack(track);
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[1].receiver.track,
+ streams: []
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {mid: null, sender: {track}},
+ {sender: {track: null}} // Created by SRD
+ ]);
+ };
+
+ const checkAddTransceiverThenAddTrackPairs = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+ pc2.addTransceiver("audio");
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc2.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: []
+ }
+ ]);
+
+ // addTransceiver-transceivers cannot attach to a remote offers, so a second
+ // transceiver is created and associated whilst the first transceiver
+ // remains unassociated.
+ assert_equals(pc2.getTransceivers()[0].mid, null);
+ assert_not_equals(pc2.getTransceivers()[1].mid, null);
+ };
+
+ const checkAddTrackPairs = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc2.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: []
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {sender: {track}}
+ ]);
+ };
+
+ const checkReplaceTrackNullDoesntPreventPairing = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.addTransceiver("audio");
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc2.addTrack(track, stream);
+ await pc2.getTransceivers()[0].sender.replaceTrack(null);
+
+ const offer = await pc1.createOffer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: []
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {sender: {track: null}}
+ ]);
+ };
+
+ const checkRemoveAndReadd = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+
+ await offerAnswer(pc1, pc2);
+
+ pc1.removeTrack(pc1.getSenders()[0]);
+ pc1.addTrack(track, stream);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: null},
+ direction: "recvonly"
+ },
+ {
+ sender: {track},
+ direction: "sendrecv"
+ }
+ ]);
+
+ // pc1 is offerer
+ await offerAnswer(pc1, pc2);
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {currentDirection: "inactive"},
+ {currentDirection: "recvonly"}
+ ]);
+
+ pc1.removeTrack(pc1.getSenders()[1]);
+ pc1.addTrack(track, stream);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: null},
+ direction: "recvonly"
+ },
+ {
+ sender: {track: null},
+ direction: "recvonly"
+ },
+ {
+ sender: {track},
+ direction: "sendrecv"
+ }
+ ]);
+
+ // pc1 is answerer. We need to create a new transceiver so pc1 will have
+ // something to attach the re-added track to
+ pc2.addTransceiver("audio");
+
+ await offerAnswer(pc2, pc1);
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {currentDirection: "inactive"},
+ {currentDirection: "inactive"},
+ {currentDirection: "sendrecv"}
+ ]);
+ };
+
+ const checkAddTrackExistingTransceiverThenRemove = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver("audio");
+ const stream = await getNoiseStream({audio: true});
+ const audio = stream.getAudioTracks()[0];
+ let sender = pc.addTrack(audio, stream);
+ pc.removeTrack(sender);
+
+ // Cause transceiver to be associated
+ await pc.setLocalDescription(await pc.createOffer());
+
+ // Make sure add/remove works still
+ sender = pc.addTrack(audio, stream);
+ pc.removeTrack(sender);
+
+ stopTracks(stream);
+ };
+
+ const checkRemoveTrackNegotiation = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ pc1.addTrack(audio, stream);
+ const video = stream.getVideoTracks()[0];
+ pc1.addTrack(video, stream);
+ // We want both a sendrecv and sendonly transceiver to test that the
+ // appropriate direction changes happen.
+ pc1.getTransceivers()[1].direction = "sendonly";
+
+ let offer = await pc1.createOffer();
+
+ // Get a reference to the stream
+ let trackEventCollector = collectTrackEvents(pc2);
+ await pc2.setRemoteDescription(offer);
+ let pc2TrackEvents = trackEventCollector.finish();
+ hasProps(pc2TrackEvents,
+ [
+ {streams: [{id: stream.id}]},
+ {streams: [{id: stream.id}]}
+ ]);
+ const receiveStream = pc2TrackEvents[0].streams[0];
+
+ // Verify that rollback causes onremovetrack to fire for the added tracks
+ let removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+ await pc2.setRemoteDescription({type: "rollback"});
+ let removedtracks = removetrackEventCollector.finish().map(e => e.track);
+ assert_equals(removedtracks.length, 2,
+ "Rollback should have removed two tracks");
+ assert_true(removedtracks.includes(pc2TrackEvents[0].track),
+ "First track should be removed");
+ assert_true(removedtracks.includes(pc2TrackEvents[1].track),
+ "Second track should be removed");
+
+ offer = await pc1.createOffer();
+
+ let addtrackEventCollector = collectAddTrackEvents(receiveStream);
+ trackEventCollector = collectTrackEvents(pc2);
+ await pc2.setRemoteDescription(offer);
+ pc2TrackEvents = trackEventCollector.finish();
+ let addedtracks = addtrackEventCollector.finish().map(e => e.track);
+ assert_equals(addedtracks.length, 2,
+ "pc2.setRemoteDescription(offer) should've added 2 tracks to receive stream");
+ assert_true(addedtracks.includes(pc2TrackEvents[0].track),
+ "First track should be added");
+ assert_true(addedtracks.includes(pc2TrackEvents[1].track),
+ "Second track should be added");
+
+ await pc1.setLocalDescription(offer);
+ let answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ pc1.removeTrack(pc1.getSenders()[0]);
+
+ hasProps(pc1.getSenders(),
+ [
+ {track: null},
+ {track: video}
+ ]);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: null},
+ direction: "recvonly"
+ },
+ {
+ sender: {track: video},
+ direction: "sendonly"
+ }
+ ]);
+
+ await negotiationNeeded(pc1);
+
+ pc1.removeTrack(pc1.getSenders()[1]);
+
+ hasProps(pc1.getSenders(),
+ [
+ {track: null},
+ {track: null}
+ ]);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: null},
+ direction: "recvonly"
+ },
+ {
+ sender: {track: null},
+ direction: "inactive"
+ }
+ ]);
+
+ // pc1 as offerer
+ offer = await pc1.createOffer();
+
+ removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+ await pc2.setRemoteDescription(offer);
+ removedtracks = removetrackEventCollector.finish().map(e => e.track);
+ assert_equals(removedtracks.length, 2, "Should have two removed tracks");
+ assert_true(removedtracks.includes(pc2TrackEvents[0].track),
+ "First track should be removed");
+ assert_true(removedtracks.includes(pc2TrackEvents[1].track),
+ "Second track should be removed");
+
+ addtrackEventCollector = collectAddTrackEvents(receiveStream);
+ await pc2.setRemoteDescription({type: "rollback"});
+ addedtracks = addtrackEventCollector.finish().map(e => e.track);
+ assert_equals(addedtracks.length, 2, "Rollback should have added two tracks");
+
+ // pc2 as offerer
+ offer = await pc2.createOffer();
+ await pc2.setLocalDescription(offer);
+ await pc1.setRemoteDescription(offer);
+ answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+
+ removetrackEventCollector = collectRemoveTrackEvents(receiveStream);
+ await pc2.setRemoteDescription(answer);
+ removedtracks = removetrackEventCollector.finish().map(e => e.track);
+ assert_equals(removedtracks.length, 2, "Should have two removed tracks");
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ currentDirection: "inactive"
+ },
+ {
+ currentDirection: "inactive"
+ }
+ ]);
+ };
+
+ const checkSetDirection = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ pc.addTransceiver("audio");
+
+ pc.getTransceivers()[0].direction = "sendonly";
+ hasProps(pc.getTransceivers(),[{direction: "sendonly"}]);
+ pc.getTransceivers()[0].direction = "recvonly";
+ hasProps(pc.getTransceivers(),[{direction: "recvonly"}]);
+ pc.getTransceivers()[0].direction = "inactive";
+ hasProps(pc.getTransceivers(),[{direction: "inactive"}]);
+ pc.getTransceivers()[0].direction = "sendrecv";
+ hasProps(pc.getTransceivers(),[{direction: "sendrecv"}]);
+ };
+
+ const checkCurrentDirection = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+ hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
+
+ let offer = await pc1.createOffer();
+ hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
+
+ await pc1.setLocalDescription(offer);
+ hasProps(pc1.getTransceivers(), [{currentDirection: null}]);
+
+ let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ hasProps(pc2.getTransceivers(), [{currentDirection: null}]);
+
+ let answer = await pc2.createAnswer();
+ hasProps(pc2.getTransceivers(), [{currentDirection: null}]);
+
+ await pc2.setLocalDescription(answer);
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ pc2.getTransceivers()[0].direction = "sendonly";
+
+ offer = await pc2.createOffer();
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ await pc2.setLocalDescription(offer);
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
+ hasProps(trackEvents, []);
+
+ hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ answer = await pc1.createAnswer();
+ hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ await pc1.setLocalDescription(answer);
+ hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
+ hasProps(trackEvents, []);
+
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
+
+ pc2.getTransceivers()[0].direction = "sendrecv";
+
+ offer = await pc2.createOffer();
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
+
+ await pc2.setLocalDescription(offer);
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendonly"}]);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, offer);
+ hasProps(trackEvents, []);
+
+ hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
+
+ answer = await pc1.createAnswer();
+ hasProps(pc1.getTransceivers(), [{currentDirection: "recvonly"}]);
+
+ await pc1.setLocalDescription(answer);
+ hasProps(pc1.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, answer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ hasProps(pc2.getTransceivers(), [{currentDirection: "sendrecv"}]);
+
+ pc2.close();
+ hasProps(pc2.getTransceivers(), [{currentDirection: "stopped"}]);
+ };
+
+ const checkSendrecvWithNoSendTrack = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTransceiver("audio");
+ pc1.getTransceivers()[0].direction = "sendrecv";
+ pc2.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+
+ let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: []
+ }
+ ]);
+
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+
+ const answer = await pc2.createAnswer();
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ // Spec language doesn't say anything about checking whether the transceiver
+ // is stopped here.
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ trickle(t, pc2, pc1);
+ await pc2.setLocalDescription(answer);
+
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+ };
+
+ const checkSendrecvWithTracklessStream = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = new MediaStream();
+ pc1.addTransceiver("audio", {streams: [stream]});
+
+ const offer = await pc1.createOffer();
+
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+ };
+
+ const checkMute = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const stream1 = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream1));
+ const audio1 = stream1.getAudioTracks()[0];
+ pc1.addTrack(audio1, stream1);
+ const countMuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "mute");
+ const countUnmuteAudio1 = countEvents(pc1.getTransceivers()[0].receiver.track, "unmute");
+
+ const video1 = stream1.getVideoTracks()[0];
+ pc1.addTrack(video1, stream1);
+ const countMuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "mute");
+ const countUnmuteVideo1 = countEvents(pc1.getTransceivers()[1].receiver.track, "unmute");
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const stream2 = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream2));
+ const audio2 = stream2.getAudioTracks()[0];
+ pc2.addTrack(audio2, stream2);
+ const countMuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "mute");
+ const countUnmuteAudio2 = countEvents(pc2.getTransceivers()[0].receiver.track, "unmute");
+
+ const video2 = stream2.getVideoTracks()[0];
+ pc2.addTrack(video2, stream2);
+ const countMuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "mute");
+ const countUnmuteVideo2 = countEvents(pc2.getTransceivers()[1].receiver.track, "unmute");
+
+
+ // Check that receive tracks start muted
+ hasProps(pc1.getTransceivers(),
+ [
+ {receiver: {track: {kind: "audio", muted: true}}},
+ {receiver: {track: {kind: "video", muted: true}}}
+ ]);
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {receiver: {track: {kind: "audio", muted: true}}},
+ {receiver: {track: {kind: "video", muted: true}}}
+ ]);
+
+ let offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+ let answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ trickle(t, pc2, pc1);
+ await pc2.setLocalDescription(answer);
+
+ let gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
+ let gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
+
+ let gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
+ let gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
+ // Jump out before waiting if a track is unmuted before RTP starts flowing.
+ assert_true(pc1.getTransceivers()[0].receiver.track.muted);
+ assert_true(pc1.getTransceivers()[1].receiver.track.muted);
+ assert_true(pc2.getTransceivers()[0].receiver.track.muted);
+ assert_true(pc2.getTransceivers()[1].receiver.track.muted);
+
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+
+
+ // Check that receive tracks are unmuted when RTP starts flowing
+ await gotUnmuteAudio1;
+ await gotUnmuteVideo1;
+ await gotUnmuteAudio2;
+ await gotUnmuteVideo2;
+
+ // Check whether disabling recv locally causes onmute
+ pc1.getTransceivers()[0].direction = "sendonly";
+ pc1.getTransceivers()[1].direction = "sendonly";
+ offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc1.setLocalDescription(offer);
+ answer = await pc2.createAnswer();
+ const gotMuteAudio1 = gotMuteEvent(pc1.getTransceivers()[0].receiver.track);
+ const gotMuteVideo1 = gotMuteEvent(pc1.getTransceivers()[1].receiver.track);
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ await gotMuteAudio1;
+ await gotMuteVideo1;
+
+ // Check whether disabling on remote causes onmute
+ pc1.getTransceivers()[0].direction = "inactive";
+ pc1.getTransceivers()[1].direction = "inactive";
+ offer = await pc1.createOffer();
+ const gotMuteAudio2 = gotMuteEvent(pc2.getTransceivers()[0].receiver.track);
+ const gotMuteVideo2 = gotMuteEvent(pc2.getTransceivers()[1].receiver.track);
+ await pc2.setRemoteDescription(offer);
+ await gotMuteAudio2;
+ await gotMuteVideo2;
+ await pc1.setLocalDescription(offer);
+ answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+
+ // Check whether onunmute fires when we turn everything on again
+ pc1.getTransceivers()[0].direction = "sendrecv";
+ pc1.getTransceivers()[1].direction = "sendrecv";
+ offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc1.setLocalDescription(offer);
+ answer = await pc2.createAnswer();
+ gotUnmuteAudio1 = gotUnmuteEvent(pc1.getTransceivers()[0].receiver.track);
+ gotUnmuteVideo1 = gotUnmuteEvent(pc1.getTransceivers()[1].receiver.track);
+ gotUnmuteAudio2 = gotUnmuteEvent(pc2.getTransceivers()[0].receiver.track);
+ gotUnmuteVideo2 = gotUnmuteEvent(pc2.getTransceivers()[1].receiver.track);
+ await pc1.setRemoteDescription(answer);
+ await pc2.setLocalDescription(answer);
+ await gotUnmuteAudio1;
+ await gotUnmuteVideo1;
+ await gotUnmuteAudio2;
+ await gotUnmuteVideo2;
+
+ // Wait a little, just in case some stray events fire
+ await new Promise(r => t.step_timeout(r, 100));
+
+ assert_equals(1, countMuteAudio1.count, "Got 1 mute event for pc1's audio track");
+ assert_equals(1, countMuteVideo1.count, "Got 1 mute event for pc1's video track");
+ assert_equals(1, countMuteAudio2.count, "Got 1 mute event for pc2's audio track");
+ assert_equals(1, countMuteVideo2.count, "Got 1 mute event for pc2's video track");
+ assert_equals(2, countUnmuteAudio1.count, "Got 2 unmute events for pc1's audio track");
+ assert_equals(2, countUnmuteVideo1.count, "Got 2 unmute events for pc1's video track");
+ assert_equals(2, countUnmuteAudio2.count, "Got 2 unmute events for pc2's audio track");
+ assert_equals(2, countUnmuteVideo2.count, "Got 2 unmute events for pc2's video track");
+ };
+
+ const checkStop = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ await pc2.setRemoteDescription(offer);
+
+ pc2.addTrack(track, stream);
+
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ let stoppedTransceiver = pc1.getTransceivers()[0];
+ let onended = new Promise(resolve => {
+ stoppedTransceiver.receiver.track.onended = resolve;
+ });
+ stoppedTransceiver.stop();
+ assert_equals(pc1.getReceivers().length, 1, 'getReceivers exposes a receiver of a stopped transceiver before negotiation');
+ assert_equals(pc1.getSenders().length, 1, 'getSenders exposes a sender of a stopped transceiver before negotiation');
+ await onended;
+ // The transceiver has [[stopping]] = true, [[stopped]] = false
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: {kind: "audio"}},
+ receiver: {track: {kind: "audio", readyState: "ended"}},
+ currentDirection: "sendrecv",
+ direction: "stopped"
+ }
+ ]);
+
+ const transceiver = pc1.getTransceivers()[0];
+
+ checkThrows(() => transceiver.sender.setParameters(
+ transceiver.sender.getParameters()),
+ "InvalidStateError", "setParameters on stopped transceiver");
+
+ const stream2 = await getNoiseStream({audio: true});
+ const track2 = stream.getAudioTracks()[0];
+ checkThrows(() => transceiver.sender.replaceTrack(track2),
+ "InvalidStateError", "replaceTrack on stopped transceiver");
+
+ checkThrows(() => transceiver.direction = "sendrecv",
+ "InvalidStateError", "set direction on stopped transceiver");
+
+ checkThrows(() => transceiver.sender.dtmf.insertDTMF("111"),
+ "InvalidStateError", "insertDTMF on stopped transceiver");
+
+ // Shouldn't throw
+ stoppedTransceiver.stop();
+
+ offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+
+ const stoppedCalleeTransceiver = pc2.getTransceivers()[0];
+ onended = new Promise(resolve => {
+ stoppedCalleeTransceiver.receiver.track.onended = resolve;
+ });
+
+ await pc2.setRemoteDescription(offer);
+
+ await onended;
+ // pc2's transceiver was stopped remotely.
+ // The track ends when setRemeoteDescription(offer) is set.
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ sender: {track: {kind: "audio"}},
+ receiver: {track: {kind: "audio", readyState: "ended"}},
+ currentDirection: "stopped",
+ direction: "stopped"
+ }
+ ]);
+ // After setLocalDescription(answer), the transceiver has
+ // [[stopping]] = true, [[stopped]] = true, and is removed from pc2.
+ const stoppingAnswer = await pc2.createAnswer();
+ await pc2.setLocalDescription(stoppingAnswer);
+ assert_equals(pc2.getTransceivers().length, 0);
+ assert_equals(pc2.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation');
+ assert_equals(pc2.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation');
+
+ // Shouldn't throw either
+ stoppedTransceiver.stop();
+ await pc1.setRemoteDescription(stoppingAnswer);
+ assert_equals(pc1.getReceivers().length, 0, 'getReceivers does not expose a receiver of a stopped transceiver after negotiation');
+ assert_equals(pc1.getSenders().length, 0, 'getSenders does not expose a sender of a stopped transceiver after negotiation');
+
+ pc1.close();
+ pc2.close();
+
+ // Spec says the closed check comes before the stopped check, so this
+ // should throw now.
+ checkThrows(() => stoppedTransceiver.stop(),
+ "InvalidStateError", "RTCRtpTransceiver.stop() with closed PC");
+ };
+
+ const checkStopAfterCreateOffer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+
+ const transceiverThatWasStopped = pc1.getTransceivers()[0];
+ transceiverThatWasStopped.stop();
+ await pc2.setRemoteDescription(offer)
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+
+ let answer = await pc2.createAnswer();
+ const negotiationNeededAwaiter = negotiationNeeded(pc1);
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ // Spec language doesn't say anything about checking whether the transceiver
+ // is stopped here.
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ assert_equals(transceiverThatWasStopped, pc1.getTransceivers()[0]);
+ // The transceiver should still be [[stopping]]=true, [[stopped]]=false.
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ currentDirection: "sendrecv",
+ direction: "stopped"
+ }
+ ]);
+
+ await negotiationNeededAwaiter;
+
+ trickle(t, pc2, pc1);
+
+ await pc2.setLocalDescription(answer);
+
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+
+ offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ assert_equals(pc1.getTransceivers().length, 0);
+ assert_equals(pc2.getTransceivers().length, 0);
+ };
+
+ const checkStopAfterSetLocalOffer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+
+ await pc2.setRemoteDescription(offer)
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+
+ pc1.getTransceivers()[0].stop();
+
+ let answer = await pc2.createAnswer();
+ const negotiationNeededAwaiter = negotiationNeeded(pc1);
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ // Spec language doesn't say anything about checking whether the transceiver
+ // is stopped here.
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: "sendrecv"
+ }
+ ]);
+ await negotiationNeededAwaiter;
+
+ trickle(t, pc2, pc1);
+ await pc2.setLocalDescription(answer);
+
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+
+ offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(pc1.getTransceivers().length, 0);
+ assert_equals(pc2.getTransceivers().length, 0);
+ };
+
+ const checkStopAfterSetRemoteOffer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+
+ await pc2.setRemoteDescription(offer)
+ await pc1.setLocalDescription(offer);
+
+ // Stop on _answerer_ side now. Should not stop transceiver in answer,
+ // but cause firing of negotiationNeeded at pc2, and disabling
+ // of the transceiver with direction = inactive in answer.
+ pc2.getTransceivers()[0].stop();
+ assert_equals(pc2.getTransceivers()[0].direction, 'stopped');
+
+ const answer = await pc2.createAnswer();
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ hasProps(trackEvents, []);
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: null,
+ }
+ ]);
+
+ const negotiationNeededAwaiter = negotiationNeeded(pc2);
+ await pc2.setLocalDescription(answer);
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: "inactive",
+ }
+ ]);
+
+ await negotiationNeededAwaiter;
+ };
+
+ const checkStopAfterCreateAnswer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+
+ await pc2.setRemoteDescription(offer)
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+
+ let answer = await pc2.createAnswer();
+
+ // Too late for this to go in the answer. ICE should succeed.
+ pc2.getTransceivers()[0].stop();
+
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: null,
+ }
+ ]);
+
+ trickle(t, pc2, pc1);
+ // The negotiationneeded event is fired during processing of
+ // setLocalDescription()
+ const negotiationNeededAwaiter = negotiationNeeded(pc2);
+ await pc2.setLocalDescription(answer);
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: "sendrecv",
+ }
+ ]);
+
+ await negotiationNeededAwaiter;
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+
+ offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+ answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ // Since this offer/answer exchange was initiated from pc1,
+ // pc2 still doesn't get to say that it has a stopped transceiver,
+ // but does get to set it to inactive.
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ direction: "sendrecv",
+ currentDirection: "inactive",
+ }
+ ]);
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: "inactive",
+ }
+ ]);
+ };
+
+ const checkStopAfterSetLocalAnswer = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+
+ await pc2.setRemoteDescription(offer)
+ trickle(t, pc1, pc2);
+ await pc1.setLocalDescription(offer);
+
+ let answer = await pc2.createAnswer();
+
+ const trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ trickle(t, pc2, pc1);
+ await pc2.setLocalDescription(answer);
+
+ // ICE should succeed.
+ pc2.getTransceivers()[0].stop();
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ direction: "stopped",
+ currentDirection: "sendrecv",
+ }
+ ]);
+
+ await negotiationNeeded(pc2);
+ await iceConnected(pc1);
+ await iceConnected(pc2);
+
+ // Initiate an offer/answer exchange from pc2 in order
+ // to negotiate the stopped transceiver.
+ offer = await pc2.createOffer();
+ await pc2.setLocalDescription(offer);
+ await pc1.setRemoteDescription(offer);
+ answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+ await pc2.setRemoteDescription(answer);
+
+ assert_equals(pc1.getTransceivers().length, 0);
+ assert_equals(pc2.getTransceivers().length, 0);
+ };
+
+ const checkStopAfterClose = async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer)
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ pc1.close();
+ await checkThrows(() => pc1.getTransceivers()[0].stop(),
+ "InvalidStateError",
+ "Stopping a transceiver on a closed PC should throw.");
+ };
+
+ const checkLocalRollback = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc.addTrack(track, stream);
+
+ let offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+
+ hasPropsAndUniqueMids(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track},
+ direction: "sendrecv",
+ currentDirection: null,
+ }
+ ]);
+
+ // Verify that rollback doesn't stomp things it should not
+ pc.getTransceivers()[0].direction = "sendonly";
+ const stream2 = await getNoiseStream({audio: true});
+ const track2 = stream2.getAudioTracks()[0];
+ await pc.getTransceivers()[0].sender.replaceTrack(track2);
+
+ await pc.setLocalDescription({type: "rollback"});
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: track2},
+ direction: "sendonly",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+
+ // Make sure stop() isn't rolled back either.
+ offer = await pc.createOffer();
+ await pc.setLocalDescription(offer);
+ pc.getTransceivers()[0].stop();
+ await pc.setLocalDescription({type: "rollback"});
+
+ hasProps(pc.getTransceivers(), [
+ {
+ direction: "stopped",
+ }
+ ]);
+ };
+
+ const checkRollbackAndSetRemoteOfferWithDifferentType = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ const audioStream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(audioStream));
+ const audioTrack = audioStream.getAudioTracks()[0];
+ pc1.addTrack(audioTrack, audioStream);
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const videoStream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stopTracks(videoStream));
+ const videoTrack = videoStream.getVideoTracks()[0];
+ pc2.addTrack(videoTrack, videoStream);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ await pc1.setLocalDescription({type: "rollback"});
+
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: audioTrack},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: videoTrack},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+
+ await offerAnswer(pc2, pc1);
+
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: audioTrack},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ },
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: null},
+ direction: "recvonly",
+ currentDirection: "recvonly",
+ }
+ ]);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: videoTrack},
+ direction: "sendrecv",
+ currentDirection: "sendonly",
+ }
+ ]);
+
+ await offerAnswer(pc1, pc2);
+ };
+
+ const checkRemoteRollback = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+
+ let offer = await pc1.createOffer();
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ await pc2.setRemoteDescription(offer);
+
+ const removedTransceiver = pc2.getTransceivers()[0];
+
+ const onended = new Promise(resolve => {
+ removedTransceiver.receiver.track.onended = resolve;
+ });
+
+ await pc2.setRemoteDescription({type: "rollback"});
+
+ // Transceiver should be _gone_
+ hasProps(pc2.getTransceivers(), []);
+
+ hasProps(removedTransceiver,
+ {
+ mid: null,
+ currentDirection: "stopped"
+ }
+ );
+
+ await onended;
+
+ hasProps(removedTransceiver,
+ {
+ receiver: {track: {readyState: "ended"}},
+ mid: null,
+ currentDirection: "stopped"
+ }
+ );
+
+ // Setting the same offer again should do the same thing as before
+ await pc2.setRemoteDescription(offer);
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ currentDirection: null,
+ }
+ ]);
+
+ const mid0 = pc2.getTransceivers()[0].mid;
+
+ // Give pc2 a track with replaceTrack
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream2));
+ const track2 = stream2.getAudioTracks()[0];
+ await pc2.getTransceivers()[0].sender.replaceTrack(track2);
+ pc2.getTransceivers()[0].direction = "sendrecv";
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: track2},
+ direction: "sendrecv",
+ mid: mid0,
+ currentDirection: null,
+ }
+ ]);
+
+ await pc2.setRemoteDescription({type: "rollback"});
+
+ // Transceiver should be _gone_, again. replaceTrack doesn't prevent this,
+ // nor does setting direction.
+ hasProps(pc2.getTransceivers(), []);
+
+ // Setting the same offer for a _third_ time should do the same thing
+ await pc2.setRemoteDescription(offer);
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ mid: mid0,
+ currentDirection: null,
+ }
+ ]);
+
+ // We should be able to add the same track again
+ pc2.addTrack(track2, stream2);
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: track2},
+ direction: "sendrecv",
+ mid: mid0,
+ currentDirection: null,
+ }
+ ]);
+
+ await pc2.setRemoteDescription({type: "rollback"});
+ // Transceiver should _not_ be gone this time, because addTrack touched it.
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: track2},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ }
+ ]);
+
+ // Complete negotiation so we can test interactions with transceiver.stop()
+ await pc1.setLocalDescription(offer);
+
+ // After all this SRD/rollback, we should still get the track event
+ let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+
+ assert_equals(trackEvents.length, 1);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+
+ // Make sure all this rollback hasn't messed up the signaling
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ assert_equals(trackEvents.length, 1);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc1.getTransceivers()[0].receiver.track,
+ streams: [{id: stream2.id}]
+ }
+ ]);
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track},
+ direction: "sendrecv",
+ mid: mid0,
+ currentDirection: "sendrecv",
+ }
+ ]);
+
+ // Don't bother waiting for ICE and such
+
+ // Check to see whether rolling back a remote track removal works
+ pc1.getTransceivers()[0].direction = "recvonly";
+ offer = await pc1.createOffer();
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents, []);
+
+ trackEvents =
+ await setRemoteDescriptionReturnTrackEvents(pc2, {type: "rollback"});
+
+ assert_equals(trackEvents.length, 1, 'track event from remote rollback');
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[0].receiver.track,
+ streams: [{id: stream.id}]
+ }
+ ]);
+
+ // Check to see that stop() cannot be rolled back
+ pc1.getTransceivers()[0].stop();
+ offer = await pc1.createOffer();
+
+ await pc2.setRemoteDescription(offer);
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: track2},
+ direction: "stopped",
+ mid: mid0,
+ currentDirection: "stopped",
+ }
+ ]);
+
+ // stop() cannot be rolled back!
+ // Transceiver should have [[stopping]]=true, [[stopped]]=false.
+ await pc2.setRemoteDescription({type: "rollback"});
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: {kind: "audio"}},
+ direction: "stopped",
+ mid: mid0,
+ currentDirection: "stopped",
+ }
+ ]);
+ };
+
+ const checkBundleTagRejected = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream1 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream1));
+ const track1 = stream1.getAudioTracks()[0];
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream2));
+ const track2 = stream2.getAudioTracks()[0];
+
+ pc1.addTrack(track1, stream1);
+ pc1.addTrack(track2, stream2);
+
+ await offerAnswer(pc1, pc2);
+
+ pc2.getTransceivers()[0].stop();
+
+ await offerAnswer(pc1, pc2);
+ await offerAnswer(pc2, pc1);
+ };
+
+ const checkMsectionReuse = async t => {
+ // Use max-compat to make it easier to check for disabled m-sections
+ const pc1 = new RTCPeerConnection({ bundlePolicy: "max-compat" });
+ const pc2 = new RTCPeerConnection({ bundlePolicy: "max-compat" });
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const track = stream.getAudioTracks()[0];
+ pc1.addTrack(track, stream);
+ const [pc1Transceiver] = pc1.getTransceivers();
+
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+
+ // Answerer stops transceiver. The m-section is not immediately rejected
+ // (a follow-up O/A exchange is needed) but it should become inactive in
+ // the meantime.
+ const stoppedMid0 = pc2.getTransceivers()[0].mid;
+ const [pc2Transceiver] = pc2.getTransceivers();
+ pc2Transceiver.stop();
+ assert_equals(pc2.getTransceivers()[0].direction, "stopped");
+ assert_not_equals(pc2.getTransceivers()[0].currentDirection, "stopped");
+
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // Still not stopped - but inactive is reflected!
+ assert_equals(pc1Transceiver.mid, stoppedMid0);
+ assert_equals(pc1Transceiver.direction, "sendrecv");
+ assert_equals(pc1Transceiver.currentDirection, "inactive");
+ assert_equals(pc2Transceiver.mid, stoppedMid0);
+ assert_equals(pc2Transceiver.direction, "stopped");
+ assert_equals(pc2Transceiver.currentDirection, "inactive");
+
+ // Now do the follow-up O/A exchange pc2 -> pc1.
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+
+ // Now they're stopped, and have been removed from the PCs.
+ assert_equals(pc1.getTransceivers().length, 0);
+ assert_equals(pc2.getTransceivers().length, 0);
+ assert_equals(pc1Transceiver.mid, null);
+ assert_equals(pc1Transceiver.direction, "stopped");
+ assert_equals(pc1Transceiver.currentDirection, "stopped");
+ assert_equals(pc2Transceiver.mid, null);
+ assert_equals(pc2Transceiver.direction, "stopped");
+ assert_equals(pc2Transceiver.currentDirection, "stopped");
+
+ // Check that m-section is reused on both ends
+ const stream2 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream2));
+ const track2 = stream2.getAudioTracks()[0];
+
+ pc1.addTrack(track2, stream2);
+ let offer = await pc1.createOffer();
+ assert_equals(offer.sdp.match(/m=/g).length, 1,
+ "Exactly one m-line in offer, because it was reused");
+ hasProps(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: track2}
+ }
+ ]);
+
+ assert_not_equals(pc1.getTransceivers()[0].mid, stoppedMid0);
+
+ pc2.addTrack(track, stream);
+ offer = await pc2.createOffer();
+ assert_equals(offer.sdp.match(/m=/g).length, 1,
+ "Exactly one m-line in offer, because it was reused");
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ sender: {track}
+ }
+ ]);
+
+ assert_not_equals(pc2.getTransceivers()[0].mid, stoppedMid0);
+
+ await pc2.setLocalDescription(offer);
+ await pc1.setRemoteDescription(offer);
+ let answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+ await pc2.setRemoteDescription(answer);
+ hasPropsAndUniqueMids(pc1.getTransceivers(),
+ [
+ {
+ sender: {track: track2},
+ currentDirection: "sendrecv"
+ }
+ ]);
+
+ const mid0 = pc1.getTransceivers()[0].mid;
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ sender: {track},
+ currentDirection: "sendrecv",
+ mid: mid0
+ }
+ ]);
+
+ // stop the transceiver, and add a track. Verify that we don't reuse
+ // prematurely in our offer. (There should be one rejected m-section, and a
+ // new one for the new track)
+ const stoppedMid1 = pc1.getTransceivers()[0].mid;
+ pc1.getTransceivers()[0].stop();
+ const stream3 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream3));
+ const track3 = stream3.getAudioTracks()[0];
+ pc1.addTrack(track3, stream3);
+ offer = await pc1.createOffer();
+ assert_equals(offer.sdp.match(/m=/g).length, 2,
+ "Exactly 2 m-lines in offer, because it is too early to reuse");
+ assert_equals(offer.sdp.match(/m=audio 0 /g).length, 1,
+ "One m-line is rejected");
+
+ await pc1.setLocalDescription(offer);
+
+ let trackEvents = await setRemoteDescriptionReturnTrackEvents(pc2, offer);
+ hasProps(trackEvents,
+ [
+ {
+ track: pc2.getTransceivers()[1].receiver.track,
+ streams: [{id: stream3.id}]
+ }
+ ]);
+
+ answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+
+ trackEvents = await setRemoteDescriptionReturnTrackEvents(pc1, answer);
+ hasProps(trackEvents, []);
+
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ sender: {track: null},
+ currentDirection: "recvonly"
+ }
+ ]);
+
+ // Verify that we don't reuse the mid from the stopped transceiver
+ const mid1 = pc2.getTransceivers()[0].mid;
+ assert_not_equals(mid1, stoppedMid1);
+
+ pc2.addTrack(track3, stream3);
+ // There are two ways to handle this new track; reuse the recvonly
+ // transceiver created above, or create a new transceiver and reuse the
+ // disabled m-section. We're supposed to do the former.
+ offer = await pc2.createOffer();
+ assert_equals(offer.sdp.match(/m=/g).length, 2, "Exactly 2 m-lines in offer");
+ assert_equals(offer.sdp.match(/m=audio 0 /g).length, 1,
+ "One m-line is rejected, because the other was used");
+
+ hasProps(pc2.getTransceivers(),
+ [
+ {
+ mid: mid1,
+ sender: {track: track3},
+ currentDirection: "recvonly",
+ direction: "sendrecv"
+ }
+ ]);
+
+ // Add _another_ track; this should reuse the disabled m-section
+ const stream4 = await getNoiseStream({audio: true});
+ t.add_cleanup(() => stopTracks(stream4));
+ const track4 = stream4.getAudioTracks()[0];
+ pc2.addTrack(track4, stream4);
+ offer = await pc2.createOffer();
+ await pc2.setLocalDescription(offer);
+ hasPropsAndUniqueMids(pc2.getTransceivers(),
+ [
+ {
+ mid: mid1
+ },
+ {
+ sender: {track: track4},
+ }
+ ]);
+
+ // Fourth transceiver should have a new mid
+ assert_not_equals(pc2.getTransceivers()[1].mid, stoppedMid0);
+ assert_not_equals(pc2.getTransceivers()[1].mid, stoppedMid1);
+
+ assert_equals(offer.sdp.match(/m=/g).length, 2,
+ "Exactly 2 m-lines in offer, because m-section was reused");
+ assert_equals(offer.sdp.match(/m=audio 0 /g), null,
+ "No rejected m-line, because it was reused");
+ };
+
+ const checkStopAfterCreateOfferWithReusedMsection = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+
+ pc1.addTrack(audio, stream);
+ pc1.addTrack(video, stream);
+
+ await offerAnswer(pc1, pc2);
+ pc1.getTransceivers()[1].stop();
+ await offerAnswer(pc1, pc2);
+
+ // Second (video) m-section has been negotiated disabled.
+ const transceiver = pc1.addTransceiver("video");
+ const offer = await pc1.createOffer();
+ transceiver.stop();
+ await pc1.setLocalDescription(offer);
+ await pc2.setRemoteDescription(offer);
+
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ };
+
+ const checkAddIceCandidateToStoppedTransceiver = async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream));
+ const audio = stream.getAudioTracks()[0];
+ const video = stream.getVideoTracks()[0];
+
+ pc1.addTrack(audio, stream);
+ pc1.addTrack(video, stream);
+
+ pc2.addTrack(audio, stream);
+ pc2.addTrack(video, stream);
+
+ await pc1.setLocalDescription(await pc1.createOffer());
+ pc1.getTransceivers()[1].stop();
+ pc1.setLocalDescription({type: "rollback"});
+
+ const offer = await pc2.createOffer();
+ await pc2.setLocalDescription(offer);
+ await pc1.setRemoteDescription(offer);
+
+ await pc1.addIceCandidate(
+ {
+ candidate: "candidate:0 1 UDP 2122252543 192.168.1.112 64261 typ host",
+ sdpMid: pc2.getTransceivers()[1].mid
+ });
+ };
+
+const tests = [
+ checkAddTransceiverNoTrack,
+ checkAddTransceiverWithTrack,
+ checkAddTransceiverWithAddTrack,
+ checkAddTransceiverWithDirection,
+ //checkMsidNoTrackId,
+ checkAddTransceiverWithSetRemoteOfferSending,
+ checkAddTransceiverWithSetRemoteOfferNoSend,
+ checkAddTransceiverBadKind,
+ checkNoMidOffer,
+ checkNoMidAnswer,
+ checkSetDirection,
+ //checkCurrentDirection,
+ checkSendrecvWithNoSendTrack,
+ checkSendrecvWithTracklessStream,
+ checkAddTransceiverNoTrackDoesntPair,
+ checkAddTransceiverWithTrackDoesntPair,
+ checkAddTransceiverThenReplaceTrackDoesntPair,
+ checkAddTransceiverThenAddTrackPairs,
+ checkAddTrackPairs,
+ checkReplaceTrackNullDoesntPreventPairing,
+ checkRemoveAndReadd,
+ checkAddTrackExistingTransceiverThenRemove,
+ //checkRemoveTrackNegotiation,
+ //checkMute,
+ //checkStop,
+ checkStopAfterCreateOffer,
+ checkStopAfterSetLocalOffer,
+ checkStopAfterSetRemoteOffer,
+ checkStopAfterCreateAnswer,
+ checkStopAfterSetLocalAnswer,
+ checkStopAfterClose,
+ checkLocalRollback,
+ checkRollbackAndSetRemoteOfferWithDifferentType,
+ //checkRemoteRollback,
+ //checkMsectionReuse,
+ checkStopAfterCreateOfferWithReusedMsection,
+ checkAddIceCandidateToStoppedTransceiver,
+ checkBundleTagRejected
+].forEach(test => promise_test(test, test.name));
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset="utf-8">
+<title>RTCSctpTransport constructor</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Test is based on the following revision:
+// https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// generateDataChannelOffer()
+// generateAnswer()
+
+/*
+ 6.1.
+
+ partial interface RTCPeerConnection {
+ readonly attribute RTCSctpTransport? sctp;
+ ...
+ };
+
+ 6.1.1.
+
+ interface RTCSctpTransport {
+ readonly attribute RTCDtlsTransport transport;
+ readonly attribute RTCSctpTransportState state;
+ readonly attribute unrestricted double maxMessageSize;
+ attribute EventHandler onstatechange;
+ };
+
+ 4.4.1.1. Constructor
+ 9. Let connection have an [[SctpTransport]] internal slot, initialized to null.
+
+ 4.4.1.6. Set the RTCSessionSessionDescription
+ 2.2.6. If description is of type "answer" or "pranswer", then run the
+ following steps:
+ 1. If description initiates the establishment of a new SCTP association, as defined in
+ [SCTP-SDP], Sections 10.3 and 10.4, create an RTCSctpTransport with an initial state
+ of "connecting" and assign the result to the [[SctpTransport]] slot.
+ */
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
+
+ const offer = await generateAudioReceiveOnlyOffer(pc1);
+ await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must remain null');
+}, 'setRemoteDescription() with answer not containing data media should not initialize pc.sctp');
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
+
+ const offer = await generateAudioReceiveOnlyOffer(pc2);
+ await Promise.all([pc2.setLocalDescription(offer), pc1.setRemoteDescription(offer)]);
+ const answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must remain null');
+}, 'setLocalDescription() with answer not containing data media should not initialize pc.sctp');
+
+function validateSctpTransport(sctp) {
+ assert_not_equals(sctp, null, 'RTCSctpTransport must be available');
+
+ assert_true(sctp instanceof RTCSctpTransport,
+ 'Expect pc.sctp to be instance of RTCSctpTransport');
+
+ assert_true(sctp.transport instanceof RTCDtlsTransport,
+ 'Expect sctp.transport to be instance of RTCDtlsTransport');
+
+ assert_equals(sctp.state, 'connecting', 'RTCSctpTransport should be in the connecting state');
+
+ // Note: Yes, Number.POSITIVE_INFINITY is also a 'number'
+ assert_equals(typeof sctp.maxMessageSize, 'number',
+ 'Expect sctp.maxMessageSize to be a number');
+}
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
+
+ const offer = await generateDataChannelOffer(pc1);
+ await Promise.all([pc1.setLocalDescription(offer), pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(answer);
+
+ validateSctpTransport(pc1.sctp);
+}, 'setRemoteDescription() with answer containing data media should initialize pc.sctp');
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ assert_equals(pc1.sctp, null, 'RTCSctpTransport must be null');
+
+ const offer = await generateDataChannelOffer(pc2);
+ await Promise.all([pc2.setLocalDescription(offer), pc1.setRemoteDescription(offer)]);
+ const answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+
+ validateSctpTransport(pc1.sctp);
+}, 'setLocalDescription() with answer containing data media should initialize pc.sctp');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCIceTransport</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('');
+ assert_equals(null, pc1.sctp);
+ assert_equals(null, pc2.sctp);
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ assert_not_equals(null, pc1.sctp);
+ await pc2.setRemoteDescription(offer);
+ assert_not_equals(null, pc2.sctp);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ // Since this test does not exchange candidates, state remains "connecting".
+ assert_equals(pc1.sctp.state, "connecting");
+ assert_equals(pc2.sctp.state, "connecting");
+}, 'SctpTransport objects are created at appropriate times');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ exchangeIceCandidates(pc1, pc2);
+ pc1.createDataChannel('');
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ const pc1ConnectedWaiter = waitForState(pc1.sctp, 'connected');
+ await pc2.setRemoteDescription(offer);
+ const pc2ConnectedWaiter = waitForState(pc2.sctp, 'connected');
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ await pc1ConnectedWaiter;
+ await pc2ConnectedWaiter;
+ const pc1ClosedWaiter = waitForState(pc1.sctp, 'closed');
+ const pc2ClosedWaiter = waitForState(pc2.sctp, 'closed');
+ pc1.close();
+ await pc1ClosedWaiter;
+ await pc2ClosedWaiter;
+}, 'SctpTransport reaches connected and closed state');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCSctpTransport.prototype.maxChannels</title>
+<link rel="help" href="https://w3c.github.io/webrtc-pc/#rtcsctptransport-interface">
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async (t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+ pc.createDataChannel('test');
+ const offer = await pc.createOffer();
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxChannels, null, 'maxChannels must not be set');
+}, 'An unconnected peerconnection must not have maxChannels set');
+
+promise_test(async (t) => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ exchangeIceCandidates(pc1, pc2);
+ pc1.createDataChannel('');
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ const pc1ConnectedWaiter = waitForState(pc1.sctp, 'connected');
+ await pc2.setRemoteDescription(offer);
+ const pc2ConnectedWaiter = waitForState(pc2.sctp, 'connected');
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+ assert_equals(null, pc1.sctp.maxChannels);
+ assert_equals(null, pc2.sctp.maxChannels);
+ await pc1ConnectedWaiter;
+ await pc2ConnectedWaiter;
+ assert_not_equals(null, pc1.sctp.maxChannels);
+ assert_not_equals(null, pc2.sctp.maxChannels);
+ assert_equals(pc1.sctp.maxChannels, pc2.sctp.maxChannels);
+}, 'maxChannels gets instantiated after connecting');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCSctpTransport.prototype.maxMessageSize</title>
+<link rel="help" href="https://w3c.github.io/webrtc-pc/#rtcsctptransport-interface">
+<script src=../../resources/testharness.js></script>
+<script src=../../resources/testharnessreport.js></script>
+<script src="support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// This test has an assert_unreached() that requires that the variable
+// canSendSize (initiated below) must be 0 or greater than 2. The reason
+// is that we need two non-zero values for testing the following two cases:
+//
+// * if remote MMS `1` < canSendSize it should result in `1`.
+// * renegotiation of the above case with remoteMMS `2` should result in `2`.
+//
+// This is a bit unfortunate but shouldn't have any practical impact.
+
+// Helper class to read SDP attributes and generate SDPs with modified attribute values
+class SDPAttributeHelper {
+ constructor(attrName, valueRegExpStr) {
+ this.attrName = attrName;
+ this.re = new RegExp(`^a=${attrName}:(${valueRegExpStr})\\r\\n`, 'm');
+ }
+
+ getValue(sdp) {
+ const matches = sdp.match(this.re);
+ return matches ? matches[1] : null;
+ }
+
+ sdpWithValue(sdp, value) {
+ const matches = sdp.match(this.re);
+ const sdpParts = sdp.split(matches[0]);
+ const attributeLine = arguments.length > 1 ? `a=${this.attrName}:${value}\r\n` : '';
+ return `${sdpParts[0]}${attributeLine}${sdpParts[1]}`;
+ }
+
+ sdpWithoutAttribute(sdp) {
+ return this.sdpWithValue(sdp);
+ }
+}
+
+const mmsAttributeHelper = new SDPAttributeHelper('max-message-size', '\\d+');
+let canSendSize = null;
+const remoteSize1 = 1;
+const remoteSize2 = 2;
+
+promise_test(async (t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+
+ let offer = await generateDataChannelOffer(pc);
+ assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
+ 'SDP should have max-message-size attribute');
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, 0) };
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ canSendSize = pc.sctp.maxMessageSize === Number.POSITIVE_INFINITY ? 0 : pc.sctp.maxMessageSize;
+ if (canSendSize !== 0 && canSendSize < remoteSize2) {
+ assert_unreached(
+ 'This test needs canSendSize to be 0 or > 2 for further "below" and "above" tests');
+ }
+}, 'Determine the local side send limitation (canSendSize) by offering a max-message-size of 0');
+
+promise_test(async (t) => {
+ assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
+
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+
+ let offer = await generateDataChannelOffer(pc);
+ assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
+ 'SDP should have max-message-size attribute');
+
+ // Remove the max-message-size SDP attribute
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithoutAttribute(offer.sdp) };
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ // Test outcome depends on canSendSize value
+ if (canSendSize !== 0) {
+ assert_equals(pc.sctp.maxMessageSize, Math.min(65536, canSendSize),
+ 'Missing SDP attribute and a non-zero canSendSize should give an maxMessageSize of min(65536, canSendSize)');
+ } else {
+ assert_equals(pc.sctp.maxMessageSize, 65536,
+ 'Missing SDP attribute and a canSendSize of 0 should give an maxMessageSize of 65536');
+ }
+}, 'Remote offer SDP missing max-message-size attribute');
+
+promise_test(async (t) => {
+ assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
+
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+
+ let offer = await generateDataChannelOffer(pc);
+ assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
+ 'SDP should have max-message-size attribute');
+
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1) };
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxMessageSize, remoteSize1,
+ 'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
+}, 'max-message-size with a (non-zero) value provided by the remote peer');
+
+promise_test(async (t) => {
+ assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
+
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+
+ let offer = await generateDataChannelOffer(pc);
+ assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
+ 'SDP should have max-message-size attribute');
+
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1) };
+ await pc.setRemoteDescription(offer);
+ let answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxMessageSize, remoteSize1,
+ 'maxMessageSize should be the value provided by the remote peer (as long as it is less than canSendSize)');
+
+ // Start new O/A exchange that updates max-message-size to remoteSize2
+ offer = await pc.createOffer();
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize2)};
+ await pc.setRemoteDescription(offer);
+ answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxMessageSize, remoteSize2,
+ 'maxMessageSize should be the new value provided by the remote peer (as long as it is less than canSendSize)');
+
+ // Start new O/A exchange that updates max-message-size to zero
+ offer = await pc.createOffer();
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, 0)};
+ await pc.setRemoteDescription(offer);
+ answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxMessageSize, canSendSize,
+ 'maxMessageSize should be canSendSize');
+
+ // Start new O/A exchange that updates max-message-size to remoteSize1 again
+ offer = await pc.createOffer();
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, remoteSize1)};
+ await pc.setRemoteDescription(offer);
+ answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ assert_equals(pc.sctp.maxMessageSize, remoteSize1,
+ 'maxMessageSize should be the new value provided by the remote peer (as long as it is less than canSendSize)');
+}, 'Renegotiate max-message-size with various values provided by the remote peer');
+
+promise_test(async (t) => {
+ assert_not_equals(canSendSize, null, 'canSendSize needs to be determined');
+
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ assert_equals(pc.sctp, null, 'RTCSctpTransport must be null');
+ const largerThanCanSendSize = canSendSize === 0 ? 0 : canSendSize + 1;
+
+ let offer = await generateDataChannelOffer(pc);
+ assert_not_equals(mmsAttributeHelper.getValue(offer.sdp), null,
+ 'SDP should have max-message-size attribute');
+
+ offer = { type: 'offer', sdp: mmsAttributeHelper.sdpWithValue(offer.sdp, largerThanCanSendSize) };
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ await pc.setLocalDescription(answer);
+
+ assert_not_equals(pc.sctp, null, 'RTCSctpTransport must be available');
+ // Test outcome depends on canSendSize value
+ if (canSendSize !== 0) {
+ assert_equals(pc.sctp.maxMessageSize, canSendSize,
+ 'A remote value larger than a non-zero canSendSize should limit maxMessageSize to canSendSize');
+ } else {
+ assert_equals(pc.sctp.maxMessageSize, Number.POSITIVE_INFINITY,
+ 'A remote value of zero and canSendSize zero should result in "infinity"');
+ }
+}, 'max-message-size with a (non-zero) value larger than canSendSize provided by the remote peer');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCTrackEvent constructor</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+ 'use strict';
+
+ // Test is based on the following editor draft:
+ // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+ /*
+ 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;
+ };
+
+ dictionary RTCTrackEventInit : EventInit {
+ required RTCRtpReceiver receiver;
+ required MediaStreamTrack track;
+ sequence<MediaStream> streams = [];
+ required RTCRtpTransceiver transceiver;
+ };
+ */
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+ const { track } = receiver;
+
+ const trackEvent = new RTCTrackEvent('track', {
+ receiver, track, transceiver
+ });
+
+ assert_equals(trackEvent.receiver, receiver);
+ assert_equals(trackEvent.track, track);
+ assert_array_equals(trackEvent.streams, []);
+ assert_array_equals(trackEvent.streams, trackEvent.streams, '[SameObject]');
+ assert_equals(trackEvent.transceiver, transceiver);
+
+ assert_equals(trackEvent.type, 'track');
+ assert_false(trackEvent.bubbles);
+ assert_false(trackEvent.cancelable);
+
+ }, `new RTCTrackEvent() with valid receiver, track, transceiver should succeed`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+ const { track } = receiver;
+
+ const stream = new MediaStream([track]);
+
+ const trackEvent = new RTCTrackEvent('track', {
+ receiver, track, transceiver,
+ streams: [stream]
+ });
+
+ assert_equals(trackEvent.receiver, receiver);
+ assert_equals(trackEvent.track, track);
+ assert_array_equals(trackEvent.streams, [stream]);
+ assert_equals(trackEvent.transceiver, transceiver);
+
+ }, `new RTCTrackEvent() with valid receiver, track, streams, transceiver should succeed`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+ const { track } = receiver;
+
+ const stream1 = new MediaStream([track]);
+ const stream2 = new MediaStream([track]);
+
+ const trackEvent = new RTCTrackEvent('track', {
+ receiver, track, transceiver,
+ streams: [stream1, stream2]
+ });
+
+ assert_equals(trackEvent.receiver, receiver);
+ assert_equals(trackEvent.track, track);
+ assert_array_equals(trackEvent.streams, [stream1, stream2]);
+ assert_equals(trackEvent.transceiver, transceiver);
+
+ }, `new RTCTrackEvent() with valid receiver, track, multiple streams, transceiver should succeed`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const receiver = pc.addTransceiver('audio').receiver;
+ const track = pc.addTransceiver('audio').receiver.track;
+
+ const stream = new MediaStream();
+
+ const trackEvent = new RTCTrackEvent('track', {
+ receiver, track, transceiver,
+ streams: [stream]
+ });
+
+ assert_equals(trackEvent.receiver, receiver);
+ assert_equals(trackEvent.track, track);
+ assert_array_equals(trackEvent.streams, [stream]);
+ assert_equals(trackEvent.transceiver, transceiver);
+
+ }, `new RTCTrackEvent() with unrelated receiver, track, streams, transceiver should succeed`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+ const { track } = receiver;
+
+ assert_throws_js(TypeError, () =>
+ new RTCTrackEvent('track', {
+ receiver, track
+ }));
+
+ }, `new RTCTrackEvent() with no transceiver should throw TypeError`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+
+ assert_throws_js(TypeError, () =>
+ new RTCTrackEvent('track', {
+ receiver, transceiver
+ }));
+
+ }, `new RTCTrackEvent() with no track should throw TypeError`);
+
+ test(t => {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { receiver } = transceiver;
+ const { track } = receiver;
+
+ assert_throws_js(TypeError, () =>
+ new RTCTrackEvent('track', {
+ track, transceiver
+ }));
+
+ }, `new RTCTrackEvent() with no receiver should throw TypeError`);
+
+ /*
+ Coverage Report
+ Interface tests are counted as 1 trivial test
+
+ Tested 1
+ Total 1
+ */
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>Change of msid in remote description should trigger related track events</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+const sdpBase =`v=0
+o=- 5511237691691746 2 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE 0
+a=ice-options:trickle
+a=ice-lite
+a=msid-semantic:WMS *
+m=audio 9 UDP/TLS/RTP/SAVPF 111 103 9 102 0 8 105 13 110 113 126
+c=IN IP6 ::
+a=rtcp:9 IN IP6 ::
+a=rtcp-mux
+a=mid:0
+a=sendrecv
+a=ice-ufrag:z0i8R3C9C4hPRWls
+a=ice-pwd:O7bPpOFAqasqoidV4yxnFVbc
+a=ice-lite
+a=fingerprint:sha-256 B7:9C:0D:C9:D1:42:57:97:82:4D:F9:B7:93:75:49:C3:42:21:5A:DD:9C:B5:ED:53:53:F0:B4:C8:AE:88:7A:E7
+a=setup:actpass
+a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
+a=extmap:9 urn:ietf:params:rtp-hdrext:sdes:mid
+a=rtpmap:0 PCMU/8000`;
+
+const sdp0 = sdpBase + `
+`;
+
+const sdp1 = sdpBase + `
+a=msid:1 2
+a=ssrc:3 cname:4
+a=ssrc:3 msid:1 2
+`;
+
+const sdp2 = sdpBase + `
+a=ssrc:3 cname:4
+a=ssrc:3 msid:1 2
+`;
+
+const sdp3 = sdpBase + `
+a=msid:1 2
+a=ssrc:3 cname:4
+a=ssrc:3 msid:3 2
+`;
+
+const sdp4 = sdp1.replace('msid-semantic', 'unknownattr');
+
+const sdp5 = sdpBase + `
+a=msid:-
+`;
+
+const sdp6 = sdpBase + `
+a=msid:1 2
+a=msid:1 2
+`;
+
+async function applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp)
+{
+ const testTrackPromise = new Promise(resolve => {
+ pc.ontrack = (event) => { resolve([event.track, event.streams]); };
+ });
+ await pc.setRemoteDescription({type: 'offer', sdp: sdp});
+ return testTrackPromise;
+}
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
+ assert_equals(streams.length, 1, "track event has a stream");
+}, "When a=msid is absent, the track should still be associated with a stream");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
+ assert_equals(streams.length, 1, "track event has a stream");
+ assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be ignored if media-level msid is present");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp2);
+ assert_equals(streams.length, 1, "track event has a stream");
+ assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be parsed if media-level msid is absent");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ let track;
+ let streams;
+ try {
+ [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp3);
+ } catch (e) {
+ return;
+ }
+ assert_equals(streams.length, 1, "track event has a stream");
+ assert_equals(streams[0].id, "1", "msid should match");
+}, "Source-level msid should be ignored, or an error should be thrown, if a different media-level msid is present");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp4);
+ assert_equals(streams.length, 1, "track event has a stream");
+ assert_equals(streams[0].id, "1", "msid should match");
+}, "stream ids should be found even if msid-semantic is absent");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ const [track, streams] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
+ assert_equals(streams.length, 1, "track event has a stream");
+ assert_equals(streams[0].id, "1", "msid should match");
+ const stream = streams[0];
+
+ await pc.setLocalDescription(await pc.createAnswer());
+
+ const testTrackPromise = new Promise((resolve) => { stream.onremovetrack = resolve; });
+ await pc.setRemoteDescription({type: 'offer', 'sdp': sdp0});
+ await testTrackPromise;
+
+ assert_equals(stream.getAudioTracks().length, 0, "stream should be empty");
+}, "Applying a remote description with removed msid should trigger firing a removetrack event on the corresponding stream");
+
+promise_test(async test => {
+ const pc = new RTCPeerConnection();
+ test.add_cleanup(() => pc.close());
+
+ let [track0, streams0] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp0);
+
+ await pc.setLocalDescription(await pc.createAnswer());
+
+ let [track1, streams1] = await applyRemoteDescriptionAndReturnRemoteTrackAndStreams(pc, sdp1);
+
+ assert_equals(streams1.length, 1, "track event has a stream");
+ assert_equals(streams1[0].id, "1", "msid should match");
+ assert_equals(streams1[0].getTracks()[0], track0, "track should match");
+}, "Applying a remote description with a new msid should trigger firing an event with populated streams");
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+['audio', 'video'].forEach((kind) => {
+ // Make sure "ontrack" fires if a prevuously rolled back track is added back.
+ promise_test(async t => {
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(track, stream);
+ pc2.addTrack(track, stream);
+ const [pc1Transceiver] = pc1.getTransceivers();
+ const [pc2Transceiver] = pc2.getTransceivers();
+
+ let remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
+
+ // Apply remote offer, but don't complete the entire exchange.
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ // The addTrack-transceiver gets associated, no need for a second
+ // transceiver.
+ assert_equals(pc2.getTransceivers().length, 1);
+ const remoteStream = await remoteStreamViaOnTrackPromise;
+ assert_equals(remoteStream.id, stream.id);
+
+ const onRemoveTrackPromise = new Promise(r => {
+ remoteStream.onremovetrack = () => { r(); };
+ });
+
+ // Cause track removal due to rollback.
+ await pc2.setLocalDescription({type:'rollback'});
+ // The track was removed.
+ await onRemoveTrackPromise;
+
+ // Sanity check that ontrack still fires if we add it back again by applying
+ // the same remote offer.
+ remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
+ await pc2.setRemoteDescription(pc1.localDescription);
+ const revivedRemoteStream = await remoteStreamViaOnTrackPromise;
+ // This test only expects IDs to be the same. The same stream object should
+ // also be used, but this should be covered by separate tests.
+ // TODO(https://crbug.com/1321738): Add MediaStream identity tests.
+ assert_equals(remoteStream.id, revivedRemoteStream.id);
+ // No cheating, the same transciever should be used as before.
+ assert_equals(pc2.getTransceivers().length, 1);
+ }, `[${kind}] Track with stream: removal due to disassociation in rollback and then add it back again`);
+
+ // This is the same test as above, but this time without any remote streams.
+ // This test could fail if [[FiredDirection]] was not reset in a rollback but
+ // the above version of the test might still pass due to the track being
+ // re-added to its stream.
+ promise_test(async t => {
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(track);
+ pc2.addTrack(track);
+ const [pc1Transceiver] = pc1.getTransceivers();
+ const [pc2Transceiver] = pc2.getTransceivers();
+
+ let remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
+
+ // Apply remote offer, but don't complete the entire exchange.
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ // The addTrack-transceiver gets associated, no need for a second
+ // transceiver.
+ assert_equals(pc2.getTransceivers().length, 1);
+ const remoteTrack = await remoteTrackPromise;
+ assert_not_equals(remoteTrack, null);
+
+ // Cause track removal due to rollback.
+ await pc2.setLocalDescription({type:'rollback'});
+ // There's nothing equivalent to stream.onremovetrack when you don't have a
+ // stream, but the track should become muted (if it isn't already).
+ if (!remoteTrack.muted) {
+ await new Promise(r => remoteTrack.onmute = () => { r(); });
+ }
+ assert_equals(remoteTrack.muted, true);
+
+ // Sanity check that ontrack still fires if we add it back again by applying
+ // the same remote offer.
+ remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
+ await pc2.setRemoteDescription(pc1.localDescription);
+ const revivedRemoteTrack = await remoteTrackPromise;
+ // We can be sure the same track is used, because the same transceiver is
+ // used (and transciever.receiver.track has same lifetime as transceiver).
+ assert_equals(pc2.getTransceivers().length, 1);
+ assert_equals(remoteTrack, revivedRemoteTrack);
+ }, `[${kind}] Track without stream: removal due to disassociation in rollback and then add it back`);
+
+ // Make sure "ontrack" can fire in a rollback (undo making it inactive).
+ promise_test(async t => {
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(track, stream);
+ const [pc1Transceiver] = pc1.getTransceivers();
+
+ let remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
+
+ // Complete O/A exchange such that the transceiver gets associated.
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+ const [pc2Transceiver] = pc2.getTransceivers();
+ assert_equals(pc2Transceiver.direction, 'recvonly');
+ assert_equals(pc2Transceiver.currentDirection, 'recvonly');
+
+ const remoteStream = await remoteStreamViaOnTrackPromise;
+ assert_equals(remoteStream.id, stream.id);
+ const onRemoveTrackPromise = new Promise(r => {
+ remoteStream.onremovetrack = () => { r(); };
+ });
+
+ // Cause track removal.
+ pc1Transceiver.direction = 'inactive';
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ // The track was removed.
+ await onRemoveTrackPromise;
+
+ // Rolling back the offer revives the track, causing ontrack to fire again.
+ remoteStreamViaOnTrackPromise = getRemoteStreamViaOnTrackPromise(pc2);
+ await pc2.setLocalDescription({type:'rollback'});
+ const revivedRemoteStream = await remoteStreamViaOnTrackPromise;
+ // This test only expects IDs to be the same. The same stream object should
+ // also be used, but this should be covered by separate tests.
+ // TODO(https://crbug.com/1321738): Add MediaStream identity tests.
+ assert_equals(remoteStream.id, revivedRemoteStream.id);
+ }, `[${kind}] Track with stream: removal due to direction changing and then add back using rollback`);
+
+ // Same test as above but without remote streams.
+ promise_test(async t => {
+ const constraints = {};
+ constraints[kind] = true;
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ pc1.addTrack(track);
+ const [pc1Transceiver] = pc1.getTransceivers();
+
+ let remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
+
+ // Complete O/A exchange such that the transceiver gets associated.
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+ const [pc2Transceiver] = pc2.getTransceivers();
+ assert_equals(pc2Transceiver.direction, 'recvonly');
+ assert_equals(pc2Transceiver.currentDirection, 'recvonly');
+
+ const remoteTrack = await remoteTrackPromise;
+
+ // Cause track removal.
+ pc1Transceiver.direction = 'inactive';
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ // There's nothing equivalent to stream.onremovetrack when you don't have a
+ // stream, but the track should become muted (if it isn't already).
+ if (!remoteTrack.muted) {
+ await new Promise(r => remoteTrack.onmute = () => { r(); });
+ }
+ assert_equals(remoteTrack.muted, true);
+
+ // Rolling back the offer revives the track, causing ontrack to fire again.
+ remoteTrackPromise = getTrackViaOnTrackPromise(pc2);
+ await pc2.setLocalDescription({type:'rollback'});
+ const revivedRemoteTrack = await remoteTrackPromise;
+ // We can be sure the same track is used, because the same transceiver is
+ // used (and transciever.receiver.track has same lifetime as transceiver).
+ assert_equals(pc2.getTransceivers().length, 1);
+ assert_equals(remoteTrack, revivedRemoteTrack);
+ }, `[${kind}] Track without stream: removal due to direction changing and then add back using rollback`);
+});
+
+function getTrackViaOnTrackPromise(pc) {
+ return new Promise(r => {
+ pc.ontrack = e => {
+ pc.ontrack = null;
+ r(e.track);
+ };
+ });
+}
+
+function getRemoteStreamViaOnTrackPromise(pc) {
+ return new Promise(r => {
+ pc.ontrack = e => {
+ pc.ontrack = null;
+ r(e.streams[0]);
+ };
+ });
+}
+
+</script>
--- /dev/null
+Coverage is based on the following editor draft:
+https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+7. insertDTMF
+
+ [Trivial]
+ - The tones parameter is treated as a series of characters.
+
+ [RTCDTMFSender-insertDTMF]
+ - The characters 0 through 9, A through D, #, and * generate the associated
+ DTMF tones.
+
+ [RTCDTMFSender-insertDTMF]
+ - The characters a to d MUST be normalized to uppercase on entry and are equivalent
+ to A to D.
+
+ [RTCDTMFSender-insertDTMF]
+ - As noted in [RTCWEB-AUDIO] Section 3, support for the characters 0 through 9,
+ A through D, #, and * are required.
+
+ [RTCDTMFSender-insertDTMF]
+ - The character ',' MUST be supported, and indicates a delay of 2 seconds before
+ processing the next character in the tones parameter.
+
+ [RTCDTMFSender-insertDTMF]
+ - All other characters (and only those other characters) MUST
+ be considered unrecognized.
+
+ [Trivial]
+ - The duration parameter indicates the duration in ms to use for each character passed
+ in the tones parameters.
+
+ [RTCDTMFSender-ontonechange]
+ - The duration cannot be more than 6000 ms or less than 40 ms.
+
+ [RTCDTMFSender-ontonechange]
+ - The default duration is 100 ms for each tone.
+
+ [RTCDTMFSender-ontonechange]
+ - The interToneGap parameter indicates the gap between tones in ms. The user agent
+ clamps it to at least 30 ms. The default value is 70 ms.
+
+ [Untestable]
+ - The browser MAY increase the duration and interToneGap times to cause the times
+ that DTMF start and stop to align with the boundaries of RTP packets but it MUST
+ not increase either of them by more than the duration of a single RTP audio packet.
+
+ [Trivial]
+ When the insertDTMF() method is invoked, the user agent MUST run the following steps:
+
+ [Trivial]
+ 1. let sender be the RTCRtpSender used to send DTMF.
+
+ [Trivial]
+ 2. Let transceiver be the RTCRtpTransceiver object associated with sender.
+
+ [RTCDTMFSender-insertDTMF]
+ 3. If transceiver.stopped is true, throw an InvalidStateError.
+
+ [RTCDTMFSender-insertDTMF]
+ 4. If transceiver.currentDirection is recvonly or inactive, throw an
+ InvalidStateError.
+
+ [Trivial]
+ 5. Let tones be the method's first argument.
+
+ [RTCDTMFSender-insertDTMF]
+ 6. If tones contains any unrecognized characters, throw an InvalidCharacterError.
+
+ [RTCDTMFSender-insertDTMF]
+ 7. Set the object's toneBuffer attribute to tones.
+
+ [RTCDTMFSender-ontonechange]
+ 8. If the value of the duration parameter is less than 40, set it to 40.
+
+ [RTCDTMFSender-ontonechange-long]
+ If, on the other hand, the value is greater than 6000, set it to 6000.
+
+ [RTCDTMFSender-ontonechange]
+ 9. If the value of the interToneGap parameter is less than 30, set it to 30.
+
+ [RTCDTMFSender-ontonechange]
+ 10. If toneBuffer is an empty string, abort these steps.
+
+ [RTCDTMFSender-ontonechange]
+ 11. If a Playout task is scheduled to be run; abort these steps;
+
+ [RTCDTMFSender-ontonechange]
+ otherwise queue a task that runs the following steps (Playout task):
+
+ [RTCDTMFSender-ontonechange]
+ 1. If transceiver.stopped is true, abort these steps.
+
+ [RTCDTMFSender-ontonechange]
+ 2. If transceiver.currentDirection is recvonly or inactive, abort these steps.
+
+ [RTCDTMFSender-ontonechange]
+ 3. If toneBuffer is an empty string, fire an event named tonechange with an
+ empty string at the RTCDTMFSender object and abort these steps.
+
+ [RTCDTMFSender-ontonechange]
+ 4. Remove the first character from toneBuffer and let that character be tone.
+
+ [Untestable]
+ 5. Start playout of tone for duration ms on the associated RTP media stream,
+ using the appropriate codec.
+
+ [RTCDTMFSender-ontonechange]
+ 6. Queue a task to be executed in duration + interToneGap ms from now that
+ runs the steps labelled Playout task.
+
+ [RTCDTMFSender-ontonechange]
+ 7. Fire an event named tonechange with a string consisting of tone at the
+ RTCDTMFSender object.
+
+Coverage Report
+
+ Tested 31
+ Not Tested 0
+ Untestable 1
+
+ Total 32
--- /dev/null
+Coverage is based on the following editor draft:
+https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+9.3 Requesting Identity Assertions
+
+ [Trivial]
+ The identity assertion request process is triggered by a call to createOffer,
+ createAnswer, or getIdentityAssertion. When these calls are invoked and an
+ identity provider has been set, the following steps are executed:
+
+ [RTCPeerConnection-getIdentityAssertion]
+ 1. The RTCPeerConnection instantiates an IdP as described in Identity Provider
+ Selection and Registering an IdP Proxy. If the IdP cannot be loaded, instantiated,
+ or the IdP proxy is not registered, this process fails.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ 2. The RTCPeerConnection invokes the generateAssertion method on the
+ RTCIdentityProvider methods registered by the IdP.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ The RTCPeerConnection generates the contents parameter to this method as
+ described in [RTCWEB-SECURITY-ARCH]. The value of contents includes the
+ fingerprint of the certificate that was selected or generated during the
+ construction of the RTCPeerConnection. The origin parameter contains the
+ origin of the script that calls the RTCPeerConnection method that triggers
+ this behavior. The usernameHint value is the same value that is provided
+ to setIdentityProvider, if any such value was provided.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ 3. The IdP proxy returns a Promise to the RTCPeerConnection. The IdP proxy is
+ expected to generate the identity assertion asynchronously.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ If the user has been authenticated by the IdP, and the IdP is able to generate
+ an identity assertion, the IdP resolves the promise with an identity assertion
+ in the form of an RTCIdentityAssertionResult .
+
+ [RTCPeerConnection-getIdentityAssertion]
+ This step depends entirely on the IdP. The methods by which an IdP authenticates
+ users or generates assertions is not specified, though they could involve
+ interacting with the IdP server or other servers.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ 4. If the IdP proxy produces an error or returns a promise that does not resolve
+ to a valid RTCIdentityValidationResult (see 9.5 IdP Error Handling), then
+ identity validation fails.
+
+ [Untestable]
+ 5. The RTCPeerConnection MAY store the identity assertion for use with future
+ offers or answers. If a fresh identity assertion is needed for any reason,
+ applications can create a new RTCPeerConnection.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ 6. If the identity request was triggered by a createOffer() or createAnswer(),
+ then the assertion is converted to a JSON string, base64-encoded and inserted
+ into an a=identity attribute in the session description.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ If assertion generation fails, then the promise for the corresponding function call
+ is rejected with a newly created OperationError.
+
+9.3.1 User Login Procedure
+ [RTCPeerConnection-getIdentityAssertion]
+ An IdP MAY reject an attempt to generate an identity assertion if it is unable to
+ verify that a user is authenticated. This might be due to the IdP not having the
+ necessary authentication information available to it (such as cookies).
+
+ [RTCPeerConnection-getIdentityAssertion]
+ Rejecting the promise returned by generateAssertion will cause the error to propagate
+ to the application. Login errors are indicated by rejecting the promise with an RTCError
+ with errorDetail set to "idp-need-login".
+
+ [RTCPeerConnection-getIdentityAssertion]
+ The URL to login at will be passed to the application in the idpLoginUrl attribute of
+ the RTCPeerConnection.
+
+ [Out of Scope]
+ An application can load the login URL in an IFRAME or popup window; the resulting page
+ then SHOULD provide the user with an opportunity to enter any information necessary to
+ complete the authorization process.
+
+ [Out of Scope]
+ Once the authorization process is complete, the page loaded in the IFRAME or popup sends
+ a message using postMessage [webmessaging] to the page that loaded it (through the
+ window.opener attribute for popups, or through window.parent for pages loaded in an IFRAME).
+ The message MUST consist of the DOMString "LOGINDONE". This message informs the application
+ that another attempt at generating an identity assertion is likely to be successful.
+
+9.4. Verifying Identity Assertions
+ The identity assertion request process involves the following asynchronous steps:
+
+ [TODO]
+ 1. The RTCPeerConnection awaits any prior identity validation. Only one identity
+ validation can run at a time for an RTCPeerConnection. This can happen because
+ the resolution of setRemoteDescription is not blocked by identity validation
+ unless there is a target peer identity.
+
+ [RTCPeerConnection-peerIdentity]
+ 2. The RTCPeerConnection loads the identity assertion from the session description
+ and decodes the base64 value, then parses the resulting JSON. The idp parameter
+ of the resulting dictionary contains a domain and an optional protocol value
+ that identifies the IdP, as described in [RTCWEB-SECURITY-ARCH].
+
+ [RTCPeerConnection-peerIdentity]
+ 3. The RTCPeerConnection instantiates the identified IdP as described in 9.1.1
+ Identity Provider Selection and 9.2 Registering an IdP Proxy. If the IdP
+ cannot be loaded, instantiated or the IdP proxy is not registered, this
+ process fails.
+
+ [RTCPeerConnection-peerIdentity]
+ 4. The RTCPeerConnection invokes the validateAssertion method registered by the IdP.
+
+ [RTCPeerConnection-peerIdentity]
+ The assertion parameter is taken from the decoded identity assertion. The origin
+ parameter contains the origin of the script that calls the RTCPeerConnection
+ method that triggers this behavior.
+
+ [RTCPeerConnection-peerIdentity]
+ 5. The IdP proxy returns a promise and performs the validation process asynchronously.
+
+ [Out of Scope]
+ The IdP proxy verifies the identity assertion using whatever means necessary.
+ Depending on the authentication protocol this could involve interacting with the
+ IdP server.
+
+ [RTCPeerConnection-peerIdentity]
+ 6. If the IdP proxy produces an error or returns a promise that does not resolve
+ to a valid RTCIdentityValidationResult (see 9.5 IdP Error Handling), then
+ identity validation fails.
+
+ [RTCPeerConnection-peerIdentity]
+ 7. Once the assertion is successfully verified, the IdP proxy resolves the promise
+ with an RTCIdentityValidationResult containing the validated identity and the
+ original contents that are the payload of the assertion.
+
+ [RTCPeerConnection-peerIdentity]
+ 8. The RTCPeerConnection decodes the contents and validates that it contains a
+ fingerprint value for every a=fingerprint attribute in the session description.
+ This ensures that the certificate used by the remote peer for communications
+ is covered by the identity assertion.
+
+ [RTCPeerConnection-peerIdentity]
+ 9. The RTCPeerConnection validates that the domain portion of the identity matches
+ the domain of the IdP as described in [RTCWEB-SECURITY-ARCH]. If this check fails
+ then the identity validation fails.
+
+ [RTCPeerConnection-peerIdentity]
+ 10. The RTCPeerConnection resolves the peerIdentity attribute with a new instance
+ of RTCIdentityAssertion that includes the IdP domain and peer identity.
+
+ [Out of Scope]
+ 11. The user agent MAY display identity information to a user in its UI. Any user
+ identity information that is displayed in this fashion MUST use a mechanism that
+ cannot be spoofed by content.
+
+ [RTCPeerConnection-peerIdentity]
+ If identity validation fails, the peerIdentity promise is rejected with a newly
+ created OperationError.
+
+ [RTCPeerConnection-peerIdentity]
+ If identity validation fails and there is a target peer identity for the
+ RTCPeerConnection, the promise returned by setRemoteDescription MUST be rejected
+ with the same DOMException.
+
+9.5. IdP Error Handling
+ [RTCPeerConnection-getIdentityAssertion]
+ - A RTCPeerConnection might be configured with an identity provider, but loading of
+ the IdP URI fails. Any procedure that attempts to invoke such an identity provider
+ and cannot load the URI fails with an RTCError with errorDetail set to
+ "idp-load-failure" and the httpRequestStatusCode attribute of the error set to the
+ HTTP status code of the response.
+
+ [Untestable]
+ - If the IdP loads fails due to the TLS certificate used for the HTTPS connection not
+ being trusted, it fails with an RTCError with errorDetail set to "idp-tls-failure".
+ This typically happens when the IdP uses certificate pinning and an intermediary
+ such as an enterprise firewall has intercepted the TLS connection.
+
+ [RTCPeerConnection-getIdentityAssertion]
+ - If the script loaded from the identity provider is not valid JavaScript or does not
+ implement the correct interfaces, it causes an IdP failure with an RTCError with
+ errorDetail set to "idp-bad-script-failure".
+
+ [TODO]
+ - An apparently valid identity provider might fail in several ways.
+
+ If the IdP token has expired, then the IdP MUST fail with an RTCError with
+ errorDetail set to "idp-token-expired".
+
+ If the IdP token is not valid, then the IdP MUST fail with an RTCError with
+ errorDetail set to "idp-token-invalid".
+
+ [Untestable]
+ - The user agent SHOULD limit the time that it allows for an IdP to 15 seconds.
+ This includes both the loading of the IdP proxy and the identity assertion
+ generation or validation. Failure to do so potentially causes the corresponding
+ operation to take an indefinite amount of time. This timer can be cancelled when
+ the IdP proxy produces a response. Expiration of this timer cases an IdP failure
+ with an RTCError with errorDetail set to "idp-timeout".
+
+ [RTCPeerConnection-getIdentityAssertion]
+ - If the identity provider requires the user to login, the operation will fail
+ RTCError with errorDetail set to "idp-need-login" and the idpLoginUrl attribute
+ of the error set to the URL that can be used to login.
+
+ [RTCPeerConnection-peerIdentity]
+ - Even when the IdP proxy produces a positive result, the procedure that uses this
+ information might still fail. Additional validation of a RTCIdentityValidationResult
+ value is still necessary. The procedure for validation of identity assertions
+ describes additional steps that are required to successfully validate the output
+ of the IdP proxy.
+
+
+Coverage Report
+
+ Tested 29
+ Not Tested 2
+ Untestable 4
+
+ Total 35
--- /dev/null
+Coverage Report is based on the following editor draft:
+https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+4.3.1.6 Set the RTCSessionSessionDescription
+
+ [Trivial]
+ 1. Let p be a new promise.
+
+ [Trivial]
+ 2. In parallel, start the process to apply description as described in [JSEP]
+ (section 5.5. and section 5.6.).
+
+ [Trivial]
+ 1. If the process to apply description fails for any reason, then user agent
+ MUST queue a task that runs the following steps:
+
+ [Untestable]
+ 1. If connection's [[IsClosed]] slot is true, then abort these steps.
+
+ [Untestable]
+ 2. If elements of the SDP were modified, then reject p with a newly created
+ InvalidModificationError and abort these steps.
+
+ [RTCPeerConnection-setLocalDescription-answer]
+ [RTCPeerConnection-setRemoteDescription-offer]
+ [RTCPeerConnection-setRemoteDescription-answer]
+ 3. If the description's type is invalid for the current signaling state of
+ connection as described in [JSEP] (section 5.5. and section 5.6.), then
+ reject p with a newly created InvalidStateError and abort these steps.
+
+ [RTCPeerConnection-setRemoteDescription-offer]
+ 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 error was detected) and abort these steps.
+
+ [Untestable]
+ 5. If the content of description is invalid, then reject p with a newly
+ created InvalidAccessError and abort these steps.
+
+ [Untestable]
+ 6. For all other errors, for example if description cannot be applied at
+ the media layer, reject p with a newly created OperationError.
+
+ [Trivial]
+ 2. If description is applied successfully, the user agent MUST queue a task
+ that runs the following steps:
+
+ [Untestable]
+ 1. If connection's [[isClosed]] slot is true, then abort these steps.
+
+ [RTCPeerConnection-setLocalDescription]
+ 2. If description is set as a local description, then run one of the
+ following steps:
+
+ [RTCPeerConnection-setLocalDescription-offer]
+ - If description is of type "offer", set connection.pendingLocalDescription
+ to description and signaling state to have-local-offer.
+
+ [RTCPeerConnection-setLocalDescription-answer]
+ - If description is of type "answer", then this completes an offer answer
+ negotiation.
+
+ Set connection's currentLocalDescription to description and
+ currentRemoteDescription to the value of pendingRemoteDescription.
+
+ Set both pendingRemoteDescription and pendingLocalDescription to null.
+ Finally set connection's signaling state to stable
+
+ [RTCPeerConnection-setLocalDescription-rollback]
+ - If description is of type "rollback", then this is a rollback. Set
+ connection.pendingLocalDescription to null and signaling state to stable.
+
+ [RTCPeerConnection-setLocalDescription-pranswer]
+ - If description is of type "pranswer", then set
+ connection.pendingLocalDescription to description and signaling state to
+ have-local-pranswer.
+
+ [RTCPeerConnection-setRemoteDescription]
+ 3. Otherwise, if description is set as a remote description, then run one of the
+ following steps:
+
+ [RTCPeerConnection-setRemoteDescription-offer]
+ - If description is of type "offer", set connection.pendingRemoteDescription
+ attribute to description and signaling state to have-remote-offer.
+
+ [RTCPeerConnection-setRemoteDescription-answer]
+ - If description is of type "answer", then this completes an offer answer
+ negotiation.
+
+ Set connection's currentRemoteDescription to description and
+ currentLocalDescription to the value of pendingLocalDescription.
+
+ Set both pendingRemoteDescription and pendingLocalDescription to null.
+
+ Finally setconnection's signaling state to stable
+
+ [RTCPeerConnection-setRemoteDescription-rollback]
+ - If description is of type "rollback", then this is a rollback.
+ Set connection.pendingRemoteDescription to null and signaling state to stable.
+
+ [RTCPeerConnection-setRemoteDescription-rollback]
+ - If description is of type "pranswer", then set
+ connection.pendingRemoteDescription to description and signaling state
+ to have-remote-pranswer.
+
+ [RTCPeerConnection-setLocalDescription]
+ [RTCPeerConnection-setRemoteDescription]
+ 4. If connection's signaling state changed above, fire a simple event named
+ signalingstatechange at connection.
+
+ [TODO]
+ 5. If description is of type "answer", and it initiates the closure of an existing
+ SCTP association, as defined in [SCTP-SDP], Sections 10.3 and 10.4, set the value
+ of connection's [[sctpTransport]] internal slot to null.
+
+ [RTCSctpTransport]
+ 6. If description is of type "answer" or "pranswer", then run the following steps:
+
+ [RTCSctpTransport]
+ 1. If description initiates the establishment of a new SCTP association,
+ as defined in [SCTP-SDP], Sections 10.3 and 10.4, set the value of connection's
+ [[sctpTransport]] internal slot to a newly created RTCSctpTransport.
+
+ [TODO]
+ 2. If description negotiates the DTLS role of the SCTP transport, and there is an
+ RTCDataChannel with a null id, then generate an ID according to
+ [RTCWEB-DATA-PROTOCOL].
+
+ [Untestable]
+ If no available ID could be generated, then run the following steps:
+
+ [Untestable]
+ 1. Let channel be the RTCDataChannel object for which an ID could not be
+ generated.
+
+ [Untestable]
+ 2. Set channel's readyState attribute to closed.
+
+ [Untestable]
+ 3. Fire an event named error with a ResourceInUse exception at channel.
+
+ [Untestable]
+ 4. Fire a simple event named close at channel.
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 7. If description is set as a local description, then run the following steps for
+ each media description in description that is not yet associated with an
+ RTCRtpTransceiver object:
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 1. Let transceiver be the RTCRtpTransceiver used to create the media
+ description.
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 2. Set transceiver's mid value to the mid of the corresponding media
+ description.
+
+ [RTCPeerConnection-ontrack]
+ 8. If description is set as a remote description, then run the following steps
+ for each media description in description:
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 1. As described by [JSEP] (section 5.9.), attempt to find an existing
+ RTCRtpTransceiver object, transceiver, to represent the media description.
+
+ [RTCPeerConnection-ontrack]
+ 2. If no suitable transceiver is found (transceiver is unset), run the following
+ steps:
+
+ [RTCPeerConnection-ontrack]
+ 1. Create an RTCRtpSender, sender, from the media description.
+
+ [RTCPeerConnection-ontrack]
+ 2. Create an RTCRtpReceiver, receiver, from the media description.
+
+ [RTCPeerConnection-ontrack]
+ 3. Create an RTCRtpTransceiver with sender, receiver and direction, and let
+ transceiver be the result.
+
+ [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.).
+
+ [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.
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 5. If the media description is rejected, and transceiver is not already stopped,
+ stop the RTCRtpTransceiver transceiver.
+
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 9. If description is of type "rollback", then run the following steps:
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 1. If the mid value of an RTCRtpTransceiver was set to a non-null value by
+ the RTCSessionDescription that is being rolled back, set the mid value
+ of that transceiver to null, as described by [JSEP] (section 4.1.8.2.).
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 2. If an RTCRtpTransceiver was created by applying the RTCSessionDescription
+ that is being rolled back, and a track has not been attached to it via
+ addTrack, remove that transceiver from connection's set of transceivers,
+ as described by [JSEP] (section 4.1.8.2.).
+
+ [TODO RTCPeerConnection-setDescription-transceiver]
+ 3. Restore the value of connection's [[SctpTransport]] internal slot to its
+ value at the last stable signaling state.
+
+ [RTCPeerConnection-onnegotiationneeded]
+ 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:
+
+ [Untestable]
+ 1. If connection's [[IsClosed]] slot is true, abort these steps.
+
+ [RTCPeerConnection-onnegotiationneeded]
+ 2. If connection's [[NegotiationNeeded]] slot is false, abort these steps.
+
+ [RTCPeerConnection-onnegotiationneeded]
+ 3. Fire a simple event named negotiationneeded at connection.
+
+ [Trivial]
+ 11. Resolve p with undefined.
+
+ [Trivial]
+ 3. Return p.
+
+
+Coverage Report
+
+ Tested 35
+ Not Tested 15
+ Untestable 8
+ Total 58
--- /dev/null
+<!doctype html>
+<!--
+This test uses data only, and thus does not require fake media devices.
+-->
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection GetStats</title>
+</head>
+<body>
+ <div id="log"></div>
+ <h2>Retrieved stats info</h2>
+ <pre>
+ <input type="button" onclick="showStats()" value="Show stats"></input>
+ <div id="stats">
+ </div>
+ </pre>
+
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script type="text/javascript">
+ var test = async_test('Can get stats from a basic WebRTC call.');
+ var statsToShow;
+ var gFirstConnection = null;
+ var gSecondConnection = null;
+
+ var onIceCandidateToFirst = test.step_func(function(event) {
+ gSecondConnection.addIceCandidate(event.candidate);
+ });
+
+ var onIceCandidateToSecond = test.step_func(function(event) {
+ gFirstConnection.addIceCandidate(event.candidate);
+ });
+
+ var getStatsRecordByType = function(stats, type) {
+ for (let stat of stats.values()) {
+ if (stat.type == type) {
+ return stat;
+ }
+ }
+ return null;
+ }
+
+ var onIceConnectionStateChange = test.step_func(function(event) {
+ // Wait until connection is established.
+ // Note - not all browsers reach 'completed' state, so we're
+ // checking for 'connected' state instead.
+ if (gFirstConnection.iceConnectionState != 'connected') {
+ return;
+ }
+ gFirstConnection.getStats()
+ .then(function(report) {
+ let reportDictionary = {};
+ for (let stats of report.values()) {
+ reportDictionary[stats.id] = stats;
+ }
+ statsToShow = JSON.stringify(reportDictionary, null, 2);
+ // Check the stats properties.
+ assert_not_equals(report, null, 'No report');
+ let sessionStat = getStatsRecordByType(report, 'peer-connection');
+ assert_not_equals(sessionStat, null, 'Did not find peer-connection stats');
+ assert_own_property(sessionStat, 'dataChannelsOpened', 'no dataChannelsOpened stat');
+ // Once every 4000 or so tests, the datachannel won't be opened when the getStats
+ // function is done, so allow both 0 and 1 datachannels.
+ assert_true(sessionStat.dataChannelsOpened == 1 || sessionStat.dataChannelsOpened == 0,
+ 'dataChannelsOpened count wrong');
+ test.done();
+ })
+ .catch(test.step_func(function(e) {
+ assert_unreached(e.name + ': ' + e.message + ': ');
+ }));
+ });
+
+ // This function starts the test.
+ test.step(function() {
+ gFirstConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gFirstConnection.close());
+ gFirstConnection.onicecandidate = onIceCandidateToFirst;
+ gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
+
+ gSecondConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gSecondConnection.close());
+ gSecondConnection.onicecandidate = onIceCandidateToSecond;
+
+ // The createDataChannel is necessary and sufficient to make
+ // sure the ICE connection be attempted.
+ gFirstConnection.createDataChannel('channel');
+ var atStep = 'Create offer';
+
+ gFirstConnection.createOffer()
+ .then(function(offer) {
+ atStep = 'Set local description at first';
+ return gFirstConnection.setLocalDescription(offer);
+ })
+ .then(function() {
+ atStep = 'Set remote description at second';
+ return gSecondConnection.setRemoteDescription(
+ gFirstConnection.localDescription);
+ })
+ .then(function() {
+ atStep = 'Create answer';
+ return gSecondConnection.createAnswer();
+ })
+ .then(function(answer) {
+ atStep = 'Set local description at second';
+ return gSecondConnection.setLocalDescription(answer);
+ })
+ .then(function() {
+ atStep = 'Set remote description at first';
+ return gFirstConnection.setRemoteDescription(
+ gSecondConnection.localDescription);
+ })
+ .catch(test.step_func(function(e) {
+ assert_unreached('Error ' + e.name + ': ' + e.message +
+ ' happened at step ' + atStep);
+ }));
+ });
+
+ function showStats() {
+ // Show the retrieved stats info
+ var showStats = document.getElementById('stats');
+ showStats.innerHTML = statsToShow;
+ }
+
+</script>
+
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<title>Historical WebRTC features</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+[
+ //'reliable',
+ 'maxRetransmitTime',
+].forEach((member) => {
+ test(() => {
+ assert_false(member in RTCDataChannel.prototype);
+ }, `RTCDataChannel member ${member} should not exist`);
+});
+
+[
+ //"addStream",
+ //"createDTMFSender",
+ //"getLocalStreams",
+ //"getRemoteStreams",
+ "getStreamById",
+ //"onaddstream",
+ //"onremovestream",
+ //"removeStream",
+ "updateIce",
+].forEach(function(name) {
+ test(function() {
+ assert_false(name in RTCPeerConnection.prototype);
+ }, "RTCPeerConnection member " + name + " should not exist");
+});
+
+[
+ "setDirection",
+].forEach(function(name) {
+ test(function() {
+ assert_false(name in RTCRtpTransceiver.prototype);
+ }, "RTCRtpTransceiver member " + name + " should not exist");
+});
+
+[
+ "DataChannel",
+ "mozRTCIceCandidate",
+ "mozRTCPeerConnection",
+ "mozRTCSessionDescription",
+ //"webkitRTCPeerConnection",
+].forEach(function(name) {
+ test(function() {
+ assert_false(name in window);
+ }, name + " interface should not exist");
+});
+</script>
--- /dev/null
+This directory contains files that test for behavior relevant to webrtc,
+particularly defined in https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection legacy addStream</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../support/RTCStats-helper.js"></script>
+<script src="../support/dictionary-helper.js"></script>
+<script>
+ 'use strict';
+
+ // The following helper functions are called from RTCPeerConnection-helper.js:
+ // getUserMediaTracksAndStreams
+
+ // The following helper functions are called from RTCStats-helper.js
+ // (depends on dictionary-helper.js):
+ // validateRtcStats
+
+ // TODO(hbos): addStream() is legacy API not in the spec. Based on discussion
+ // whether to standardize in legacy section, consider removing this test or
+ // keeping it until addTrack() has wide support.
+ // https://github.com/w3c/webrtc-pc/issues/1705
+ // https://github.com/w3c/webrtc-pc/issues/1125
+ async_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ let track;
+ let stream;
+ getUserMediaTracksAndStreams(1)
+ .then(t.step_func(([tracks, streams]) => {
+ track = tracks[0];
+ stream = streams[0];
+ stream.addTrack(track);
+ pc.addStream(stream);
+ return pc.createOffer();
+ }))
+ .then(t.step_func(offer => {
+ return pc.setLocalDescription(offer);
+ }))
+ .then(t.step_func(() => {
+ return pc.getStats();
+ }))
+ .then(t.step_func(report => {
+ let trackStats = findStatsByTypeAndId(report, 'track', track.id);
+ let streamStats = findStatsByTypeAndId(report, 'stream', stream.id);
+ assert_true(trackStats != null && streamStats != null,
+ 'Has stats for track and stream');
+ assert_array_equals(streamStats.trackIds, [ trackStats.id ],
+ 'streamStats.trackIds == [ trackStats.id ]');
+ validateRtcStats(report, trackStats);
+ validateRtcStats(report, streamStats);
+ t.done();
+ }))
+ .catch(t.step_func(reason => {
+ assert_unreached(reason);
+ }));
+ }, 'Legacy addStream(): Media stream stats references track stats');
+
+ function findStatsByTypeAndId(report, type, identifier) {
+ return findStats(report, stats => {
+ return stats.type == type && stats[type + 'Identifier'] == identifier;
+ });
+ }
+
+ function findStats(report, findFunc) {
+ for (let it = report.values(), n = it.next(); !n.done; n = it.next()) {
+ if (findFunc(n.value))
+ return n.value;
+ }
+ return null;
+ }
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>Test legacy offerToReceiveAudio/Video options</title>
+<link rel="help" href="https://w3c.github.io/webrtc-pc/#legacy-configuration-extensions">
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ /*
+ * 4.3.3.2 Configuration data extensions
+ * partial dictionary RTCOfferOptions
+ */
+
+ /*
+ * offerToReceiveAudio of type boolean
+ * When this is given a non-false value, no outgoing track of type
+ * "audio" is attached to the PeerConnection, and the existing
+ * localDescription (if any) doesn't contain any sendrecv or recv
+ * audio media sections, createOffer() will behave as if
+ * addTransceiver("audio") had been called once prior to the createOffer() call.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer({ offerToReceiveAudio: true })
+ .then(offer1 => {
+ assert_equals(countAudioLine(offer1.sdp), 1,
+ 'Expect created offer to have audio line');
+
+ // The first createOffer implicitly calls addTransceiver('audio'),
+ // so all following offers will also have audio media section
+ // in their SDP.
+ return pc.createOffer({ offerToReceiveAudio: false })
+ .then(offer2 => {
+ assert_equals(countAudioLine(offer2.sdp), 1,
+ 'Expect audio line to remain in created offer');
+ })
+ });
+ }, 'createOffer() with offerToReceiveAudio should add audio line to all subsequent created offers');
+
+ /*
+ * offerToReceiveVideo of type boolean
+ * When this is given a non-false value, and no outgoing track
+ * of type "video" is attached to the PeerConnection, and the
+ * existing localDescription (if any) doesn't contain any sendecv
+ * or recv video media sections, createOffer() will behave as if
+ * addTransceiver("video") had been called prior to the createOffer() call.
+ */
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer({ offerToReceiveVideo: true })
+ .then(offer1 => {
+ assert_equals(countVideoLine(offer1.sdp), 1,
+ 'Expect created offer to have video line');
+
+ return pc.createOffer({ offerToReceiveVideo: false })
+ .then(offer2 => {
+ assert_equals(countVideoLine(offer2.sdp), 1,
+ 'Expect video line to remain in created offer');
+ })
+ });
+ }, 'createOffer() with offerToReceiveVideo should add video line to all subsequent created offers');
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer({
+ offerToReceiveAudio: true,
+ offerToReceiveVideo: false
+ }).then(offer1 => {
+ assert_equals(countAudioLine(offer1.sdp), 1,
+ 'Expect audio line to be found in created offer');
+
+ assert_equals(countVideoLine(offer1.sdp), 0,
+ 'Expect video line to not be found in create offer');
+
+ return pc.createOffer({
+ offerToReceiveAudio: false,
+ offerToReceiveVideo: true
+ }).then(offer2 => {
+ assert_equals(countAudioLine(offer2.sdp), 1,
+ 'Expect audio line to remain in created offer');
+
+ assert_equals(countVideoLine(offer2.sdp), 1,
+ 'Expect video line to be found in create offer');
+ })
+ });
+ }, 'createOffer() with offerToReceiveAudio:true, then with offerToReceiveVideo:true, should have result offer with both audio and video line');
+
+
+ // Run some tests for both audio and video kinds
+ ['audio', 'video'].forEach((kind) => {
+ const capsKind = kind[0].toUpperCase() + kind.slice(1);
+
+ const offerToReceiveTrue = {};
+ offerToReceiveTrue[`offerToReceive${capsKind}`] = true;
+
+ const offerToReceiveFalse = {};
+ offerToReceiveFalse[`offerToReceive${capsKind}`] = false;
+
+ // Start testing
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const dummy = pc.createDataChannel('foo'); // Just to have something to offer
+
+ return pc.createOffer(offerToReceiveFalse)
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 0,
+ 'Expect pc to have no transceivers');
+ });
+ }, `createOffer() with offerToReceive${capsKind} set to false should not create a transceiver`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer(offerToReceiveTrue)
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'recvonly',
+ 'Expect transceiver to have "recvonly" direction');
+ });
+ }, `createOffer() with offerToReceive${capsKind} should create a "recvonly" transceiver`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer(offerToReceiveTrue)
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'recvonly',
+ 'Expect transceiver to have "recvonly" direction');
+ })
+ .then(() => pc.createOffer(offerToReceiveTrue))
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to still have only one transceiver');
+ })
+ ;
+ }, `offerToReceive${capsKind} option should be ignored if a non-stopped "recvonly" transceiver exists`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return getTrackFromUserMedia(kind)
+ .then(([track, stream]) => {
+ pc.addTrack(track, stream);
+ return pc.createOffer();
+ })
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'sendrecv',
+ 'Expect transceiver to have "sendrecv" direction');
+ })
+ .then(() => pc.createOffer(offerToReceiveTrue))
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to still have only one transceiver');
+ })
+ ;
+ }, `offerToReceive${capsKind} option should be ignored if a non-stopped "sendrecv" transceiver exists`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return getTrackFromUserMedia(kind)
+ .then(([track, stream]) => {
+ pc.addTrack(track, stream);
+ return pc.createOffer(offerToReceiveFalse);
+ })
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'sendonly',
+ 'Expect transceiver to have "sendonly" direction');
+ })
+ ;
+ }, `offerToReceive${capsKind} set to false with a track should create a "sendonly" transceiver`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver(kind, {direction: 'recvonly'});
+
+ return pc.createOffer(offerToReceiveFalse)
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'inactive',
+ 'Expect transceiver to have "inactive" direction');
+ })
+ ;
+ }, `offerToReceive${capsKind} set to false with a "recvonly" transceiver should change the direction to "inactive"`);
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const pc2 = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc2.close());
+
+ return getTrackFromUserMedia(kind)
+ .then(([track, stream]) => {
+ pc.addTrack(track, stream);
+ return pc.createOffer();
+ })
+ .then((offer) => pc.setLocalDescription(offer))
+ .then(() => pc2.setRemoteDescription(pc.localDescription))
+ .then(() => pc2.createAnswer())
+ .then((answer) => pc2.setLocalDescription(answer))
+ .then(() => pc.setRemoteDescription(pc2.localDescription))
+ .then(() => pc.createOffer(offerToReceiveFalse))
+ .then((offer) => {
+ assert_equals(pc.getTransceivers().length, 1,
+ 'Expect pc to have one transceiver');
+
+ const transceiver = pc.getTransceivers()[0];
+ assert_equals(transceiver.direction, 'sendonly',
+ 'Expect transceiver to have "sendonly" direction');
+ })
+ ;
+ }, `subsequent offerToReceive${capsKind} set to false with a track should change the direction to "sendonly"`);
+ });
+
+ promise_test(t => {
+ const pc = new RTCPeerConnection();
+
+ t.add_cleanup(() => pc.close());
+
+ return pc.createOffer({ offerToReceiveAudio: true, offerToReceiveVideo: true })
+ .then(() => {
+ assert_equals(pc.getTransceivers().length, 2,
+ 'Expect pc to have two transceivers');
+
+ assert_equals(pc.getTransceivers()[0].direction, 'recvonly',
+ 'Expect first transceiver to have "recvonly" direction');
+ assert_equals(pc.getTransceivers()[1].direction, 'recvonly',
+ 'Expect second transceiver to have "recvonly" direction');
+ });
+ }, 'offerToReceiveAudio and Video should create two "recvonly" transceivers');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCRtpTransceiver with OfferToReceive legacy options</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ const stopTracks = (...streams) => {
+ streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
+ };
+
+ // comparable() - produces copy of object that is JSON comparable.
+ // o = original object (required)
+ // t = template of what to examine. Useful if o is non-enumerable (optional)
+
+ const comparable = (o, t = o) => {
+ if (typeof o != 'object' || !o) {
+ return o;
+ }
+ if (Array.isArray(t) && Array.isArray(o)) {
+ return o.map((n, i) => comparable(n, t[i]));
+ }
+ return Object.keys(t).sort()
+ .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
+ };
+
+ const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
+
+ const hasProps = (observed, expected) => {
+ const observable = comparable(observed, expected);
+ assert_equals(stripKeyQuotes(JSON.stringify(observable)),
+ stripKeyQuotes(JSON.stringify(comparable(expected))));
+ };
+
+ const checkAddTransceiverWithStream = async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ await setMediaPermission();
+ const audioStream = await navigator.mediaDevices.getUserMedia({audio: true});
+ const videoStream = await navigator.mediaDevices.getUserMedia({video: true});
+ t.add_cleanup(() => stopTracks(audioStream, videoStream));
+
+ const audio = audioStream.getAudioTracks()[0];
+ const video = videoStream.getVideoTracks()[0];
+
+ pc.addTransceiver(audio, {streams: [audioStream]});
+ pc.addTransceiver(video, {streams: [videoStream]});
+
+ hasProps(pc.getTransceivers(),
+ [
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: audio},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ stopped: false
+ },
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: video},
+ direction: "sendrecv",
+ mid: null,
+ currentDirection: null,
+ stopped: false
+ }
+ ]);
+
+ const offer = await pc.createOffer();
+ assert_true(offer.sdp.includes("a=msid:" + audioStream.id),
+ "offer contains the expected audio msid");
+ assert_true(offer.sdp.includes("a=msid:" + videoStream.id),
+ "offer contains the expected video msid");
+ };
+
+ const checkAddTransceiverWithOfferToReceive = async (t, kinds) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const propsToSet = kinds.map(kind => {
+ if (kind == "audio") {
+ return "offerToReceiveAudio";
+ } else if (kind == "video") {
+ return "offerToReceiveVideo";
+ }
+ });
+
+ const options = {};
+
+ for (const prop of propsToSet) {
+ options[prop] = true;
+ }
+
+ let offer = await pc.createOffer(options);
+
+ const expected = [];
+
+ if (options.offerToReceiveAudio) {
+ expected.push(
+ {
+ receiver: {track: {kind: "audio"}},
+ sender: {track: null},
+ direction: "recvonly",
+ mid: null,
+ currentDirection: null,
+ stopped: false
+ });
+ }
+
+ if (options.offerToReceiveVideo) {
+ expected.push(
+ {
+ receiver: {track: {kind: "video"}},
+ sender: {track: null},
+ direction: "recvonly",
+ mid: null,
+ currentDirection: null,
+ stopped: false
+ });
+ }
+
+ hasProps(pc.getTransceivers(), expected);
+
+ // Test offerToReceive: false
+ for (const prop of propsToSet) {
+ options[prop] = false;
+ }
+
+ // Check that sendrecv goes to sendonly
+ for (const transceiver of pc.getTransceivers()) {
+ transceiver.direction = "sendrecv";
+ }
+
+ for (const transceiverCheck of expected) {
+ transceiverCheck.direction = "sendonly";
+ }
+
+ offer = await pc.createOffer(options);
+ hasProps(pc.getTransceivers(), expected);
+
+ // Check that recvonly goes to inactive
+ for (const transceiver of pc.getTransceivers()) {
+ transceiver.direction = "recvonly";
+ }
+
+ for (const transceiverCheck of expected) {
+ transceiverCheck.direction = "inactive";
+ }
+
+ offer = await pc.createOffer(options);
+ hasProps(pc.getTransceivers(), expected);
+ };
+
+const tests = [
+ checkAddTransceiverWithStream,
+ function checkAddTransceiverWithOfferToReceiveAudio(t) {
+ return checkAddTransceiverWithOfferToReceive(t, ["audio"]);
+ },
+ function checkAddTransceiverWithOfferToReceiveVideo(t) {
+ return checkAddTransceiverWithOfferToReceive(t, ["video"]);
+ },
+ function checkAddTransceiverWithOfferToReceiveBoth(t) {
+ return checkAddTransceiverWithOfferToReceive(t, ["audio", "video"]);
+ }
+].forEach(test => promise_test(test, test.name));
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>onaddstream tests</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+ 'use strict';
+
+ const stopTracks = (...streams) => {
+ streams.forEach(stream => stream.getTracks().forEach(track => track.stop()));
+ };
+
+ const collectEvents = (target, name, check) => {
+ const events = [];
+ const handler = e => {
+ check(e);
+ events.push(e);
+ };
+
+ target.addEventListener(name, handler);
+
+ const finishCollecting = () => {
+ target.removeEventListener(name, handler);
+ return events;
+ };
+
+ return {finish: finishCollecting};
+ };
+
+ const collectAddTrackEvents = stream => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(stream.getTracks().includes(e.track),
+ "track in addtrack event is in the stream");
+ };
+ return collectEvents(stream, "addtrack", checkEvent);
+ };
+
+ const collectRemoveTrackEvents = stream => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(!stream.getTracks().includes(e.track),
+ "track in removetrack event is not in the stream");
+ };
+ return collectEvents(stream, "removetrack", checkEvent);
+ };
+
+ const collectTrackEvents = pc => {
+ const checkEvent = e => {
+ assert_true(e.track instanceof MediaStreamTrack, "Track is set on event");
+ assert_true(e.receiver instanceof RTCRtpReceiver, "Receiver is set on event");
+ assert_true(e.transceiver instanceof RTCRtpTransceiver, "Transceiver is set on event");
+ assert_true(Array.isArray(e.streams), "Streams is set on event");
+ e.streams.forEach(stream => {
+ assert_true(stream.getTracks().includes(e.track),
+ "Each stream in event contains the track");
+ });
+ assert_equals(e.receiver, e.transceiver.receiver,
+ "Receiver belongs to transceiver");
+ assert_equals(e.track, e.receiver.track,
+ "Track belongs to receiver");
+ };
+
+ return collectEvents(pc, "track", checkEvent);
+ };
+
+ // comparable() - produces copy of object that is JSON comparable.
+ // o = original object (required)
+ // t = template of what to examine. Useful if o is non-enumerable (optional)
+
+ const comparable = (o, t = o) => {
+ if (typeof o != 'object' || !o) {
+ return o;
+ }
+ if (Array.isArray(t) && Array.isArray(o)) {
+ return o.map((n, i) => comparable(n, t[i]));
+ }
+ return Object.keys(t).sort()
+ .reduce((r, key) => (r[key] = comparable(o[key], t[key]), r), {});
+ };
+
+ const stripKeyQuotes = s => s.replace(/"(\w+)":/g, "$1:");
+
+ const hasProps = (observed, expected) => {
+ const observable = comparable(observed, expected);
+ assert_equals(stripKeyQuotes(JSON.stringify(observable)),
+ stripKeyQuotes(JSON.stringify(comparable(expected))));
+ };
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ await setMediaPermission();
+ const stream1 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream1));
+ const audio1 = stream1.getAudioTracks()[0];
+ pc1.addTrack(audio1, stream1);
+ const video1 = stream1.getVideoTracks()[0];
+ pc1.addTrack(video1, stream1);
+
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+ const stream2 = await navigator.mediaDevices.getUserMedia({audio: true, video: true});
+ t.add_cleanup(() => stopTracks(stream2));
+ const audio2 = stream2.getAudioTracks()[0];
+ pc2.addTrack(audio2, stream2);
+ const video2 = stream2.getVideoTracks()[0];
+ pc2.addTrack(video2, stream2);
+
+ const offer = await pc1.createOffer();
+
+ let trackEventCollector = collectTrackEvents(pc2);
+ let addstreamEventCollector = collectEvents(pc2, "addstream", e => {
+ hasProps(e, {stream: {id: stream1.id}});
+ assert_equals(e.stream.getAudioTracks().length, 1, "One audio track");
+ assert_equals(e.stream.getVideoTracks().length, 1, "One video track");
+ });
+
+ await pc2.setRemoteDescription(offer);
+
+ let addstreamEvents = addstreamEventCollector.finish();
+ assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event");
+
+ let trackEvents = trackEventCollector.finish();
+
+ hasProps(trackEvents,
+ [
+ {streams: [addstreamEvents[0].stream]},
+ {streams: [addstreamEvents[0].stream]}
+ ]);
+
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+
+ trackEventCollector = collectTrackEvents(pc1);
+ addstreamEventCollector = collectEvents(pc1, "addstream", e => {
+ hasProps(e, {stream: {id: stream2.id}});
+ assert_equals(e.stream.getAudioTracks().length, 1, "One audio track");
+ assert_equals(e.stream.getVideoTracks().length, 1, "One video track");
+ });
+
+ await pc1.setRemoteDescription(answer);
+ addstreamEvents = addstreamEventCollector.finish();
+ assert_equals(addstreamEvents.length, 1, "Should have 1 addstream event");
+
+ trackEvents = trackEventCollector.finish();
+
+ hasProps(trackEvents,
+ [
+ {streams: [addstreamEvents[0].stream]},
+ {streams: [addstreamEvents[0].stream]}
+ ]);
+ },"Check onaddstream");
+</script>
--- /dev/null
+<!doctype html>
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection No-Media Connection Test</title>
+</head>
+<body>
+ <div id="log"></div>
+ <h2>iceConnectionState info</h2>
+ <div id="stateinfo">
+ </div>
+
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script src="support/RTCPeerConnection-helper.js"></script>
+ <script type="text/javascript">
+ let gFirstConnection = null;
+ let gSecondConnection = null;
+
+ function onIceCandidate(otherConnction, event, reject) {
+ try {
+ otherConnction.addIceCandidate(event.candidate);
+ } catch(e) {
+ reject(e);
+ }
+ };
+
+ function onIceConnectionStateChange(done, failed) {
+ try {
+ assert_equals(event.type, 'iceconnectionstatechange');
+ assert_not_equals(gFirstConnection.iceConnectionState, "failed",
+ "iceConnectionState of first connection");
+ assert_not_equals(gSecondConnection.iceConnectionState, "failed",
+ "iceConnectionState of second connection");
+ const stateinfo = document.getElementById('stateinfo');
+ stateinfo.innerHTML = 'First: ' + gFirstConnection.iceConnectionState
+ + '<br>Second: ' + gSecondConnection.iceConnectionState;
+ // Note: All these combinations are legal states indicating that the
+ // call has connected. All browsers should end up in completed/completed,
+ // but as of this moment, we've chosen to terminate the test early.
+ // TODO: Revise test to ensure completed/completed is reached.
+ const allowedStates = [ 'connected', 'completed'];
+ if (allowedStates.includes(gFirstConnection.iceConnectionState) &&
+ allowedStates.includes(gSecondConnection.iceConnectionState)) {
+ done();
+ }
+ } catch(e) {
+ failed(e);
+ }
+ };
+
+ // This function starts the test.
+ promise_test((test) => {
+ return new Promise(async (resolve, reject) => {
+ gFirstConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gFirstConnection.close());
+ gFirstConnection.onicecandidate =
+ (event) => onIceCandidate(gSecondConnection, event, reject);
+ gFirstConnection.oniceconnectionstatechange =
+ () => onIceConnectionStateChange(resolve, reject);
+
+ gSecondConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gSecondConnection.close());
+ gSecondConnection.onicecandidate =
+ (event) => onIceCandidate(gFirstConnection, event, reject);
+ gSecondConnection.oniceconnectionstatechange =
+ () => onIceConnectionStateChange(resolve, reject);
+
+ const offer = await generateVideoReceiveOnlyOffer(gFirstConnection);
+
+ await gFirstConnection.setLocalDescription(offer);
+
+ // This would normally go across the application's signaling solution.
+ // In our case, the "signaling" is to call this function.
+
+ await gSecondConnection.setRemoteDescription({ type: 'offer',
+ sdp: offer.sdp });
+
+ const answer = await gSecondConnection.createAnswer();
+
+ await gSecondConnection.setLocalDescription(answer);
+
+ assert_equals(gSecondConnection.getSenders().length, 1);
+ assert_not_equals(gSecondConnection.getSenders()[0], null);
+ assert_not_equals(gSecondConnection.getSenders()[0].transport, null);
+
+ // Similarly, this would go over the application's signaling solution.
+ await gFirstConnection.setRemoteDescription({ type: 'answer',
+ sdp: answer.sdp });
+
+ // The test is terminated by onIceConnectionStateChange() calling resolve
+ // once both connections are connected.
+ })
+ });
+</script>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<!doctype html>
+<!--
+This test uses data only, and thus does not require fake media devices.
+-->
+
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection Data-Only Connection Test with Promises</title>
+</head>
+<body>
+ <div id="log"></div>
+ <h2>iceConnectionState info</h2>
+ <div id="stateinfo">
+ </div>
+
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script type="text/javascript">
+ var test = async_test('Can set up a basic WebRTC call with only data using promises.');
+
+ var gFirstConnection = null;
+ var gSecondConnection = null;
+
+ var onIceCandidateToFirst = test.step_func(function(event) {
+ gSecondConnection.addIceCandidate(event.candidate);
+ });
+
+ var onIceCandidateToSecond = test.step_func(function(event) {
+ gFirstConnection.addIceCandidate(event.candidate);
+ });
+
+ var onIceConnectionStateChange = test.step_func(function(event) {
+ assert_equals(event.type, 'iceconnectionstatechange');
+ var stateinfo = document.getElementById('stateinfo');
+ stateinfo.innerHTML = 'First: ' + gFirstConnection.iceConnectionState
+ + '<br>Second: ' + gSecondConnection.iceConnectionState;
+ // Note: All these combinations are legal states indicating that the
+ // call has connected. All browsers should end up in completed/completed,
+ // but as of this moment, we've chosen to terminate the test early.
+ // TODO: Revise test to ensure completed/completed is reached.
+ if (gFirstConnection.iceConnectionState == 'connected' &&
+ gSecondConnection.iceConnectionState == 'connected') {
+ test.done()
+ }
+ if (gFirstConnection.iceConnectionState == 'connected' &&
+ gSecondConnection.iceConnectionState == 'completed') {
+ test.done()
+ }
+ if (gFirstConnection.iceConnectionState == 'completed' &&
+ gSecondConnection.iceConnectionState == 'connected') {
+ test.done()
+ }
+ if (gFirstConnection.iceConnectionState == 'completed' &&
+ gSecondConnection.iceConnectionState == 'completed') {
+ test.done()
+ }
+ });
+
+ // This function starts the test.
+ test.step(function() {
+ gFirstConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gFirstConnection.close());
+ gFirstConnection.onicecandidate = onIceCandidateToFirst;
+ gFirstConnection.oniceconnectionstatechange = onIceConnectionStateChange;
+
+ gSecondConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gSecondConnection.close());
+ gSecondConnection.onicecandidate = onIceCandidateToSecond;
+ gSecondConnection.oniceconnectionstatechange = onIceConnectionStateChange;
+
+ // The createDataChannel is necessary and sufficient to make
+ // sure the ICE connection be attempted.
+ gFirstConnection.createDataChannel('channel');
+
+ var atStep = 'Create offer';
+
+ gFirstConnection.createOffer()
+ .then(function(offer) {
+ atStep = 'Set local description at first';
+ return gFirstConnection.setLocalDescription(offer);
+ })
+ .then(function() {
+ atStep = 'Set remote description at second';
+ return gSecondConnection.setRemoteDescription(
+ gFirstConnection.localDescription);
+ })
+ .then(function() {
+ atStep = 'Create answer';
+ return gSecondConnection.createAnswer();
+ })
+ .then(function(answer) {
+ atStep = 'Set local description at second';
+ return gSecondConnection.setLocalDescription(answer);
+ })
+ .then(function() {
+ atStep = 'Set remote description at first';
+ return gFirstConnection.setRemoteDescription(
+ gSecondConnection.localDescription);
+ })
+ .then(function() {
+ atStep = 'Negotiation completed';
+ })
+ .catch(test.step_func(function(e) {
+ assert_unreached('Error ' + e.name + ': ' + e.message +
+ ' happened at step ' + atStep);
+ }));
+ });
+</script>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>RTCPeerConnection RTP payload types</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+
+// Test that when creating an offer we do not run out of valid payload types.
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+
+ pc1.addTransceiver('audio', { direction: 'recvonly' });
+ pc1.addTransceiver('video', { direction: 'recvonly' });
+ const offer = await pc1.createOffer();
+
+ // Extract all payload types from the m= lines.
+ const payloadTypes = offer.sdp.split('\n')
+ .map(line => line.trim())
+ .filter(line => line.startsWith('m='))
+ .map(line => line.split(' ').slice(3).join(' '))
+ .join(' ')
+ .split(' ')
+ .map(payloadType => parseInt(payloadType, 10));
+
+ // The list of allowed payload types is taken from here
+ // https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-1.
+ const forbiddenPayloadTypes = payloadTypes
+ .filter(payloadType => {
+ if (payloadType >= 96 && payloadType <= 127) {
+ return false;
+ }
+ if (payloadType >= 72 && payloadType < 96) {
+ return true;
+ }
+ if (payloadType >= 35 && payloadType < 72) {
+ return false;
+ }
+ // TODO: Check against static payload type list.
+ return false;
+ });
+ assert_equals(forbiddenPayloadTypes.length, 0)
+}, 'createOffer with the maximum set of codecs does not generate invalid payload types');
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection BUNDLE</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => caller.addTrack(track, stream));
+
+ let metadataToBeLoaded;
+ callee.ontrack = (e) => {
+ const stream = e.streams[0];
+ const v = document.createElement('video');
+ v.autoplay = true;
+ v.srcObject = stream;
+ v.id = stream.id
+ metadataToBeLoaded = new Promise((resolve) => {
+ v.addEventListener('loadedmetadata', () => {
+ resolve();
+ });
+ });
+ };
+ exchangeIceCandidates(caller, callee);
+ const offer = await caller.createOffer();
+ // remove the a=group:BUNDLE from the SDP when signaling.
+ const sdp = offer.sdp.replace(/a=group:BUNDLE (.*)\r\n/, '');
+ await callee.setRemoteDescription({type: 'offer', sdp});
+ await caller.setLocalDescription(offer);
+
+ const answer = await callee.createAnswer();
+ await caller.setRemoteDescription(answer);
+ await callee.setLocalDescription(answer);
+
+ await metadataToBeLoaded;
+ const senders = caller.getSenders();
+ const dtlsTransports = senders.map(s => s.transport);
+ assert_equals(dtlsTransports.length, 2);
+ assert_not_equals(dtlsTransports[0], dtlsTransports[1]);
+
+ const iceTransports = dtlsTransports.map(t => t.iceTransport);
+ assert_equals(iceTransports.length, 2);
+ assert_not_equals(iceTransports[0], iceTransports[1]);
+}, 'not negotiating BUNDLE creates two separate ice and dtls transports');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => caller.addTrack(track, stream));
+
+ let metadataToBeLoaded;
+ callee.ontrack = (e) => {
+ const stream = e.streams[0];
+ const v = document.createElement('video');
+ v.autoplay = true;
+ v.srcObject = stream;
+ v.id = stream.id
+ metadataToBeLoaded = new Promise((resolve) => {
+ v.addEventListener('loadedmetadata', () => {
+ resolve();
+ });
+ });
+ };
+ exchangeIceCandidates(caller, callee);
+ const offer = await caller.createOffer();
+ await callee.setRemoteDescription(offer);
+ await caller.setLocalDescription(offer);
+ const secondTransport = caller.getSenders()[1].transport; // Save a reference to this transport.
+
+ const answer = await callee.createAnswer();
+ await caller.setRemoteDescription(answer);
+ await callee.setLocalDescription(answer);
+
+ await metadataToBeLoaded;
+ const senders = caller.getSenders();
+ const dtlsTransports = senders.map(s => s.transport);
+ assert_equals(dtlsTransports.length, 2);
+ assert_equals(dtlsTransports[0], dtlsTransports[1]);
+ assert_not_equals(dtlsTransports[1], secondTransport);
+ assert_equals(secondTransport.state, 'closed');
+}, 'bundles on the first transport and closes the second');
+
+</script>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>Candidate exchange</title>
+<meta name=timeout content=long>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+<script>
+
+class StateLogger {
+ constructor(source, eventname, field) {
+ source.addEventListener(eventname, event => {
+ this.events.push(source[field]);
+ });
+ this.events = [source[field]];
+ }
+}
+
+class IceStateLogger extends StateLogger {
+ constructor(source) {
+ super(source, 'iceconnectionstatechange', 'iceConnectionState');
+ }
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('datachannel');
+ pc1IceStates = new IceStateLogger(pc1);
+ pc2IceStates = new IceStateLogger(pc1);
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ // Note - it's been claimed that this state sometimes jumps straight
+ // to "completed". If so, this test should be flaky.
+ await waitForIceStateChange(pc1, ['connected']);
+ assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+ assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Two way ICE exchange works');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1IceStates = new IceStateLogger(pc1);
+ pc2IceStates = new IceStateLogger(pc1);
+ let candidates = [];
+ pc1.createDataChannel('datachannel');
+ pc1.onicecandidate = e => {
+ candidates.push(e.candidate);
+ }
+ // Candidates from PC2 are not delivered to pc1, so pc1 will use
+ // peer-reflexive candidates.
+ await exchangeOfferAnswer(pc1, pc2);
+ const waiter = waitForIceGatheringState(pc1, ['complete']);
+ await waiter;
+ for (const candidate of candidates) {
+ if (candidate) {
+ pc2.addIceCandidate(candidate);
+ }
+ }
+ await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+ waitForIceStateChange(pc2, ['connected', 'completed'])]);
+ const candidate_pair = pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
+ assert_equals(candidate_pair.local.type, 'host');
+ assert_equals(candidate_pair.remote.type, 'prflx');
+ assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+ assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Adding only caller -> callee candidates gives a connection');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1IceStates = new IceStateLogger(pc1);
+ pc2IceStates = new IceStateLogger(pc1);
+ let candidates = [];
+ pc1.createDataChannel('datachannel');
+ pc2.onicecandidate = e => {
+ candidates.push(e.candidate);
+ }
+ // Candidates from pc1 are not delivered to pc2. so pc2 will use
+ // peer-reflexive candidates.
+ await exchangeOfferAnswer(pc1, pc2);
+ const waiter = waitForIceGatheringState(pc2, ['complete']);
+ await waiter;
+ for (const candidate of candidates) {
+ if (candidate) {
+ pc1.addIceCandidate(candidate);
+ }
+ }
+ await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+ waitForIceStateChange(pc2, ['connected', 'completed'])]);
+ const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
+ assert_equals(candidate_pair.local.type, 'host');
+ assert_equals(candidate_pair.remote.type, 'prflx');
+ assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+ assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Adding only callee -> caller candidates gives a connection');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1IceStates = new IceStateLogger(pc1);
+ pc2IceStates = new IceStateLogger(pc1);
+ let pc2ToPc1Candidates = [];
+ pc1.createDataChannel('datachannel');
+ pc2.onicecandidate = e => {
+ pc2ToPc1Candidates.push(e.candidate);
+ // This particular test verifies that candidates work
+ // properly if added from the pc2 onicecandidate event.
+ if (!e.candidate) {
+ for (const candidate of pc2ToPc1Candidates) {
+ if (candidate) {
+ pc1.addIceCandidate(candidate);
+ }
+ }
+ }
+ }
+ // Candidates from |pc1| are not delivered to |pc2|. |pc2| will use
+ // peer-reflexive candidates.
+ await exchangeOfferAnswer(pc1, pc2);
+ await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+ waitForIceStateChange(pc2, ['connected', 'completed'])]);
+ const candidate_pair = pc2.sctp.transport.iceTransport.getSelectedCandidatePair();
+ assert_equals(candidate_pair.local.type, 'host');
+ assert_equals(candidate_pair.remote.type, 'prflx');
+ assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+ assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Adding callee -> caller candidates from end-of-candidates gives a connection');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1IceStates = new IceStateLogger(pc1);
+ pc2IceStates = new IceStateLogger(pc1);
+ let pc1ToPc2Candidates = [];
+ let pc2ToPc1Candidates = [];
+ pc1.createDataChannel('datachannel');
+ pc1.onicecandidate = e => {
+ pc1ToPc2Candidates.push(e.candidate);
+ }
+ pc2.onicecandidate = e => {
+ pc2ToPc1Candidates.push(e.candidate);
+ }
+ const offer = await pc1.createOffer();
+ await Promise.all([pc1.setLocalDescription(offer),
+ pc2.setRemoteDescription(offer)]);
+ const answer = await pc2.createAnswer();
+ await waitForIceGatheringState(pc1, ['complete']);
+ await pc2.setLocalDescription(answer).then(() => {
+ for (const candidate of pc1ToPc2Candidates) {
+ if (candidate) {
+ pc2.addIceCandidate(candidate);
+ }
+ }
+ });
+ await waitForIceGatheringState(pc2, ['complete']);
+ pc1.setRemoteDescription(answer).then(async () => {
+ for (const candidate of pc2ToPc1Candidates) {
+ if (candidate) {
+ await pc1.addIceCandidate(candidate);
+ }
+ }
+ });
+ await Promise.all([waitForIceStateChange(pc1, ['connected', 'completed']),
+ waitForIceStateChange(pc2, ['connected', 'completed'])]);
+ const candidate_pair =
+ pc1.sctp.transport.iceTransport.getSelectedCandidatePair();
+ assert_equals(candidate_pair.local.type, 'host');
+ // When we supply remote candidates, we expect a jump to the 'host' candidate,
+ // but it might also remain as 'prflx'.
+ assert_true(candidate_pair.remote.type == 'host' ||
+ candidate_pair.remote.type == 'prflx');
+ assert_array_equals(pc1IceStates.events, ['new', 'checking', 'connected']);
+ assert_array_equals(pc2IceStates.events, ['new', 'checking', 'connected']);
+}, 'Explicit offer/answer exchange gives a connection');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ pc1.createDataChannel('datachannel');
+ pc1.onicecandidate = assert_unreached;
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+ await new Promise(resolve => {
+ pc1.onicecandidate = resolve;
+ });
+}, 'Candidates always arrive after setLocalDescription(offer) resolves');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('datachannel');
+ pc2.onicecandidate = assert_unreached;
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ await new Promise(resolve => {
+ pc2.onicecandidate = resolve;
+ });
+}, 'Candidates always arrive after setLocalDescription(answer) resolves');
+
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.createOffer</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../support/RTCStats-helper.js"></script>
+<script>
+'use strict';
+
+// draft-ietf-rtcweb-security-20 section 6.5
+//
+// All Implementations MUST support DTLS 1.2 with the
+// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 cipher suite and the P-256
+// curve [FIPS186].
+// ....... The DTLS-SRTP protection profile
+// SRTP_AES128_CM_HMAC_SHA1_80 MUST be supported for SRTP.
+// Implementations MUST favor cipher suites which support (Perfect
+// Forward Secrecy) PFS over non-PFS cipher suites and SHOULD favor AEAD
+// over non-AEAD cipher suites.
+
+const acceptableTlsVersions = new Set([
+ 'FEFD', // DTLS 1.2 - RFC 6437 section 4.1
+ '0304', // TLS 1.3 - RFC 8446 section 5.1
+]);
+
+const acceptableDtlsCiphersuites = new Set([
+ 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',
+]);
+
+const acceptableSrtpCiphersuites = new Set([
+ 'SRTP_AES128_CM_HMAC_SHA1_80',
+ 'AES_CM_128_HMAC_SHA1_80',
+]);
+
+const acceptableTlsGroups = new Set([
+ 'P-256',
+]);
+
+const acceptableValues = {
+ 'tlsVersion': acceptableTlsVersions,
+ 'dtlsCipher': acceptableDtlsCiphersuites,
+ 'srtpCipher': acceptableSrtpCiphersuites,
+ //'tlsGroup': acceptableTlsGroups,
+};
+
+function verifyStat(name, transportStats) {
+ assert_not_equals(typeof transportStats, 'undefined');
+ assert_true(name in transportStats, 'Value present:');
+ assert_true(acceptableValues[name].has(transportStats[name]));
+}
+
+for (const name of Object.keys(acceptableValues)) {
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('foo');
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForState(pc1.sctp.transport, 'connected');
+ const statsReport = await pc1.getStats();
+ const transportStats = findStatsFromReport(statsReport,
+ stats => stats.type === 'transport')
+ verifyStat(name, transportStats);
+ }, name + ' is acceptable on data-only');
+
+ promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ const transceiver = pc1.addTransceiver('video');
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForState(transceiver.sender.transport, 'connected');
+ const statsReport = await pc1.getStats();
+ const transportStats = findStatsFromReport(statsReport,
+ stats => stats.type === 'transport')
+ verifyStat(name, transportStats);
+ }, name + ' is acceptable on video-only');
+}
+</script>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>DTLS fingerprint validation</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+<script>
+
+// Tests that an invalid fingerprint leads to a connectionState 'failed'.
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ pc1.createDataChannel('datachannel');
+ exchangeIceCandidates(pc1, pc2);
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription(offer);
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc1.setRemoteDescription(new RTCSessionDescription({
+ type: answer.type,
+ sdp: answer.sdp.replace(/a=fingerprint:sha-256 .*/g,
+ 'a=fingerprint:sha-256 00:00:00:00:00:00:00:00:00:00:00:00:00:' +
+ '00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00'),
+ }));
+ await pc2.setLocalDescription(answer);
+
+ await waitForConnectionStateChange(pc1, ['failed']);
+ await waitForConnectionStateChange(pc2, ['failed']);
+}, 'Connection fails if one side provides a wrong DTLS fingerprint');
+</script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection a=setup SDP parameter test</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+// Tests for correct behavior of DTLS a=setup parameter.
+
+// SDP copied from JSEP Example 7.1
+// It contains two media streams with different ufrags, and bundle
+// turned on.
+const kSdp = `v=0
+o=- 4962303333179871722 1 IN IP4 0.0.0.0
+s=-
+t=0 0
+a=ice-options:trickle
+a=group:BUNDLE a1 v1
+a=group:LS a1 v1
+m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
+c=IN IP4 203.0.113.100
+a=mid:a1
+a=sendrecv
+a=rtpmap:96 opus/48000/2
+a=rtpmap:0 PCMU/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:97 telephone-event/8000
+a=rtpmap:98 telephone-event/48000
+a=maxptime:120
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
+a=ice-ufrag:ETEn
+a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10101 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+m=video 10102 UDP/TLS/RTP/SAVPF 100 101
+c=IN IP4 203.0.113.100
+a=mid:v1
+a=sendrecv
+a=rtpmap:100 VP8/90000
+a=rtpmap:101 rtx/90000
+a=fmtp:101 apt=100
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=rtcp-fb:100 ccm fir
+a=rtcp-fb:100 nack
+a=rtcp-fb:100 nack pli
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
+a=ice-ufrag:BGKk
+a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10103 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+`;
+
+for (let setup of ['actpass']) {
+ promise_test(async t => {
+ const sdp = kSdp.replace(/a=setup:actpass/g,
+ 'a=setup:' + setup);
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ await pc1.setRemoteDescription({type: 'offer', sdp: sdp});
+ const answer = await pc1.createAnswer();
+ const resultingSetup = answer.sdp.match(/a=setup:\S+/);
+ if (setup === 'active') {
+ assert_equals(resultingSetup[0], 'a=setup:passive');
+ } else if (setup === 'passive') {
+ assert_equals(resultingSetup[0], 'a=setup:active');
+ } else if (setup === 'actpass') {
+ // For actpass, either active or passive are legal, although
+ // active is RECOMMENDED by RFC 5763 / 8842.
+ assert_in_array(resultingSetup[0], ['a=setup:active', 'a=setup:passive']);
+ }
+ await pc1.setLocalDescription(answer);
+ }, 'PC should accept initial offer with setup=' + setup);
+}
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection Handovers</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const offerPc = new RTCPeerConnection();
+ const answerPcFirst = new RTCPeerConnection();
+ const answerPcSecond = new RTCPeerConnection();
+ t.add_cleanup(() => {
+ offerPc.close();
+ answerPcFirst.close();
+ answerPcSecond.close();
+ });
+ const offerDatachannel1 = offerPc.createDataChannel('initial');
+ exchangeIceCandidates(offerPc, answerPcFirst);
+
+ // Negotiate connection with PC 1
+ const offer1 = await offerPc.createOffer();
+ await offerPc.setLocalDescription(offer1);
+ await answerPcFirst.setRemoteDescription(offer1);
+ const answer1 = await answerPcFirst.createAnswer();
+ await offerPc.setRemoteDescription(answer1);
+ await answerPcFirst.setLocalDescription(answer1);
+ const datachannelAtAnswerPcFirst = await new Promise(
+ r => answerPcFirst.ondatachannel = ({channel}) => r(channel));
+ const iceTransport = offerPc.sctp.transport;
+ // Check that messages get through.
+ datachannelAtAnswerPcFirst.send('hello');
+ const message1 = await awaitMessage(offerDatachannel1);
+ assert_equals(message1, 'hello');
+
+ // Renegotiate with PC 2
+ // Note - ICE candidates will also be sent to answerPc1, but that shouldn't matter.
+ exchangeIceCandidates(offerPc, answerPcSecond);
+ const offer2 = await offerPc.createOffer();
+ await offerPc.setLocalDescription(offer2);
+ await answerPcSecond.setRemoteDescription(offer2);
+ const answer2 = await answerPcSecond.createAnswer();
+ await offerPc.setRemoteDescription(answer2);
+ await answerPcSecond.setLocalDescription(answer2);
+
+ // Kill the first PC. This should not affect anything, but leaving it may cause untoward events.
+ answerPcFirst.close();
+
+ const answerDataChannel2 = answerPcSecond.createDataChannel('second back');
+
+ const datachannelAtOfferPcSecond = await new Promise(r => offerPc.ondatachannel = ({channel}) => r(channel));
+
+ await new Promise(r => datachannelAtOfferPcSecond.onopen = r);
+
+ datachannelAtOfferPcSecond.send('hello again');
+ const message2 = await awaitMessage(answerDataChannel2);
+ assert_equals(message2, 'hello again');
+}, 'Handover with datachannel reinitiated from new callee completes');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Handovers</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const offerPc = new RTCPeerConnection();
+ const answerPcFirst = new RTCPeerConnection();
+ const answerPcSecond = new RTCPeerConnection();
+ t.add_cleanup(() => {
+ offerPc.close();
+ answerPcFirst.close();
+ answerPcSecond.close();
+ });
+ offerPc.addTransceiver('audio');
+ // Negotiate connection with PC 1
+ const offer1 = await offerPc.createOffer();
+ await offerPc.setLocalDescription(offer1);
+ await answerPcFirst.setRemoteDescription(offer1);
+ const answer1 = await answerPcFirst.createAnswer();
+ await offerPc.setRemoteDescription(answer1);
+ await answerPcFirst.setLocalDescription(answer1);
+ // Renegotiate with PC 2
+ const offer2 = await offerPc.createOffer();
+ await offerPc.setLocalDescription(offer2);
+ await answerPcSecond.setRemoteDescription(offer2);
+ const answer2 = await answerPcSecond.createAnswer();
+ await offerPc.setRemoteDescription(answer2);
+ await answerPcSecond.setLocalDescription(answer2);
+}, 'Negotiation of handover initiated at caller works');
+
+promise_test(async t => {
+ const offerPc = new RTCPeerConnection();
+ const answerPcFirst = new RTCPeerConnection();
+ const answerPcSecond = new RTCPeerConnection();
+ t.add_cleanup(() => {
+ offerPc.close();
+ answerPcFirst.close();
+ answerPcSecond.close();
+ });
+ offerPc.addTransceiver('audio');
+ // Negotiate connection with PC 1
+ const offer1 = await offerPc.createOffer();
+ await offerPc.setLocalDescription(offer1);
+ await answerPcFirst.setRemoteDescription(offer1);
+ const answer1 = await answerPcFirst.createAnswer();
+ await offerPc.setRemoteDescription(answer1);
+ await answerPcFirst.setLocalDescription(answer1);
+ // Renegotiate with PC 2
+ // The offer from PC 2 needs to be consistent on at least the following:
+ // - Number, type and order of media sections
+ // - MID values
+ // - Payload type values
+ // Do a "fake" offer/answer using the original offer against PC2 to achieve this.
+ await answerPcSecond.setRemoteDescription(offer1);
+ // Discard the output of this round.
+ await answerPcSecond.setLocalDescription(await answerPcSecond.createAnswer());
+
+ // Now we can initiate an offer from the new PC.
+ const offer2 = await answerPcSecond.createOffer();
+ await answerPcSecond.setLocalDescription(offer2);
+ await offerPc.setRemoteDescription(offer2);
+ const answer2 = await offerPc.createAnswer();
+ await answerPcSecond.setRemoteDescription(answer2);
+ await offerPc.setLocalDescription(answer2);
+}, 'Negotiation of handover initiated at callee works');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection Failed State</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Tests for correct behavior of ICE state.
+
+// SDP copied from JSEP Example 7.1
+// It contains two media streams with different ufrags, and bundle
+// turned on.
+const kSdp = `v=0
+o=- 4962303333179871722 1 IN IP4 0.0.0.0
+s=-
+t=0 0
+a=ice-options:trickle
+a=group:BUNDLE a1 v1
+a=group:LS a1 v1
+m=audio 10100 UDP/TLS/RTP/SAVPF 96 0 8 97 98
+c=IN IP4 203.0.113.100
+a=mid:a1
+a=sendrecv
+a=rtpmap:96 opus/48000/2
+a=rtpmap:0 PCMU/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:97 telephone-event/8000
+a=rtpmap:98 telephone-event/48000
+a=maxptime:120
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=extmap:2 urn:ietf:params:rtp-hdrext:ssrc-audio-level
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f83006c5-a0ff-4e0a-9ed9-d3e6747be7d9
+a=ice-ufrag:ETEn
+a=ice-pwd:OtSK0WpNtpUjkY4+86js7ZQl
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10101 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+m=video 10102 UDP/TLS/RTP/SAVPF 100 101
+c=IN IP4 203.0.113.100
+a=mid:v1
+a=sendrecv
+a=rtpmap:100 VP8/90000
+a=rtpmap:101 rtx/90000
+a=fmtp:101 apt=100
+a=extmap:1 urn:ietf:params:rtp-hdrext:sdes:mid
+a=rtcp-fb:100 ccm fir
+a=rtcp-fb:100 nack
+a=rtcp-fb:100 nack pli
+a=msid:47017fee-b6c1-4162-929c-a25110252400 f30bdb4a-5db8-49b5-bcdc-e0c9a23172e0
+a=ice-ufrag:BGKk
+a=ice-pwd:mqyWsAjvtKwTGnvhPztQ9mIf
+a=fingerprint:sha-256 19:E2:1C:3B:4B:9F:81:E6:B8:5C:F4:A5:A8:D8:73:04:BB:05:2F:70:9F:04:A9:0E:05:E9:26:33:E8:70:88:A2
+a=setup:actpass
+a=dtls-id:1
+a=rtcp:10103 IN IP4 203.0.113.100
+a=rtcp-mux
+a=rtcp-rsize
+`;
+
+// Returns a promise that resolves when |pc.iceConnectionState| is in one of the
+// wanted states, and rejects if it is in one of the unwanted states.
+// This is a variant of the function in RTCPeerConnection-helper.js.
+function waitForIceStateChange(pc, wantedStates, unwantedStates=[]) {
+ return new Promise((resolve, reject) => {
+ if (wantedStates.includes(pc.iceConnectionState)) {
+ resolve();
+ return;
+ } else if (unwantedStates.includes(pc.iceConnectionState)) {
+ reject('Unexpected state encountered: ' + pc.iceConnectionState);
+ return;
+ }
+ pc.addEventListener('iceconnectionstatechange', () => {
+ if (wantedStates.includes(pc.iceConnectionState)) {
+ resolve();
+ } else if (unwantedStates.includes(pc.iceConnectionState)) {
+ reject('Unexpected state encountered: ' + pc.iceConnectionState);
+ }
+ });
+ });
+}
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ let [track, streams] = await getTrackFromUserMedia('video');
+ const sender = pc1.addTrack(track);
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ await waitForIceStateChange(pc1, ['connected', 'completed']);
+}, 'PC should enter connected (or completed) state when candidates are sent');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ let [track, streams] = await getTrackFromUserMedia('video');
+ const sender = pc1.addTrack(track);
+ const offer = await pc1.createOffer();
+ assert_greater_than_equal(offer.sdp.search('a=ice-options:trickle'), 0);
+}, 'PC should generate offer with a=ice-options:trickle');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ await pc1.setRemoteDescription({type: 'offer', sdp: kSdp});
+ const answer = await pc1.createAnswer();
+ await pc1.setLocalDescription(answer);
+ assert_greater_than_equal(answer.sdp.search('a=ice-options:trickle'), 0);
+ // When we use trickle ICE, and don't signal end-of-caniddates, we
+ // expect failure to result in 'disconnected' state rather than 'failed'.
+ const stateWaiter = waitForIceStateChange(pc1, ['disconnected'],
+ ['failed']);
+ // Add a bogus candidate. The candidate is drawn from the
+ // IANA "test-net-3" pool (RFC5737), so is guaranteed not to respond.
+ const candidateStr1 =
+ 'candidate:1 1 udp 2113929471 203.0.113.100 10100 typ host';
+ await pc1.addIceCandidate({candidate: candidateStr1,
+ sdpMid: 'a1',
+ usernameFragment: 'ETEn'});
+ await stateWaiter;
+}, 'PC should enter disconnected state when a failing candidate is sent');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection Failed State</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+// Tests for validating ice-ufrag and ice-pwd syntax defined in
+// https://tools.ietf.org/html/rfc5245#section-15.4
+// Alphanumeric, '+' and '/' are allowed.
+
+const preamble = `v=0
+o=- 0 3 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
+m=video 1 RTP/SAVPF 100
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendonly
+a=mid:video
+a=rtpmap:100 VP8/30
+a=setup:actpass
+`;
+const valid_ufrag = 'a=ice-ufrag:ETEn\r\n';
+const valid_pwd = 'a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l\r\n';
+const not_ice_char = '$'; // A snowman emoji would be cool but is not interoperable.
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const sdp = preamble +
+ valid_ufrag.replace('ETEn', 'E' + not_ice_char + 'En') +
+ valid_pwd;
+
+ return promise_rejects_dom(t, 'InvalidAccessError',
+ pc.setRemoteDescription({type: 'offer', sdp}));
+}, 'setRemoteDescription with a ice-ufrag containing a non-ice-char fails');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ const sdp = preamble +
+ valid_ufrag +
+ valid_pwd.replace('K0Wp', 'K' + not_ice_char + 'Wp');
+
+ return promise_rejects_dom(t, 'InvalidAccessError',
+ pc.setRemoteDescription({type: 'offer', sdp}));
+}, 'setRemoteDescription with a ice-pwd containing a non-ice-char fails');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.createOffer</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+ 'use strict';
+
+ // Tests for the construction of initial offers according to
+ // draft-ietf-rtcweb-jsep-24 section 5.2.1
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const offer = await generateVideoReceiveOnlyOffer(pc);
+ let offer_lines = offer.sdp.split('\r\n');
+ // The first 3 lines are dictated by JSEP.
+ assert_equals(offer_lines[0], "v=0");
+ assert_equals(offer_lines[1].slice(0, 2), "o=");
+
+ assert_regexp_match(offer_lines[1], /^o=\S+ \d+ \d+ IN IP4 \S+$/);
+ const fields = RegExp(/^o=\S+ (\d+) (\d+) IN IP4 (\S+)/).exec(offer_lines[1]);
+ // Per RFC 3264, the sess-id should be representable in an uint64
+ // Note: JSEP -24 has this wrong - see bug:
+ // https://github.com/rtcweb-wg/jsep/issues/855
+ assert_less_than(Number(fields[1]), 2**64);
+ // Per RFC 3264, the version should be less than 2^62 to avoid overflow
+ assert_less_than(Number(fields[2]), 2**62);
+ // JSEP says that the address part SHOULD be a meaningless address
+ // "such as" IN IP4 0.0.0.0. This is to prevent unintentional disclosure
+ // of IP addresses, so this is important enough to verify. Right now we
+ // allow 127.0.0.1 and 0.0.0.0, but there are other things we could allow.
+ // Maybe 0.0.0.0/8, 127.0.0.0/8, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24?
+ // (See RFC 3330, RFC 5737)
+ assert_true(fields[3] == "0.0.0.0" || fields[3] == "127.0.0.1",
+ fields[3] + " must be a meaningless IPV4 address")
+
+ assert_regexp_match(offer_lines[2], /^s=\S+$/);
+ // After this, the order is not dictated by JSEP.
+ // TODO: Check lines subsequent to the s= line.
+ }, 'Offer conforms to basic SDP requirements');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerconnection SDP parse tests</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+function removeSdpLines(description, toRemove) {
+ const edited = description.sdp.split('\n').filter(function(line) {
+ return (!line.startsWith(toRemove));
+ }).join('\n');
+ return {type: description.type, sdp: edited};
+}
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ t.add_cleanup(() => callee.close());
+ caller.addTrack(trackFactories.audio());
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ let remote_offer = removeSdpLines(offer, 'a=mid:');
+ remote_offer = removeSdpLines(remote_offer, 'a=group:');
+ await callee.setRemoteDescription(remote_offer);
+ const answer = await callee.createAnswer();
+ await caller.setRemoteDescription(answer);
+}, 'Offer description with no mid is accepted');
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ t.add_cleanup(() => callee.close());
+ caller.addTrack(trackFactories.audio());
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ let remote_answer = removeSdpLines(answer, 'a=mid:');
+ remote_answer = removeSdpLines(remote_answer, 'a=group:');
+ await caller.setRemoteDescription(remote_answer);
+}, 'Answer description with no mid is accepted');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerconnection MSID parsing</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+const preamble = `v=0
+o=- 0 3 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
+a=ice-ufrag:6HHHdzzeIhkE0CKj
+a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew
+m=video 1 RTP/SAVPF 100
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendonly
+a=mid:video
+a=rtpmap:100 VP8/30
+a=setup:actpass
+`;
+
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const ontrackPromise = addEventListenerPromise(t, pc, 'track');
+ await pc.setRemoteDescription({type: 'offer', sdp: preamble});
+ const trackevent = await ontrackPromise;
+ assert_equals(pc.getReceivers().length, 1);
+ assert_equals(trackevent.streams.length, 1, 'Stream count');
+}, 'Description with no msid produces a track with a stream');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const ontrackPromise = addEventListenerPromise(t, pc, 'track');
+ await pc.setRemoteDescription({type: 'offer',
+ sdp: preamble + 'a=msid:- foobar\n'});
+ const trackevent = await ontrackPromise;
+ assert_equals(pc.getReceivers().length, 1);
+ assert_equals(trackevent.streams.length, 0);
+}, 'Description with msid:- appid produces a track with no stream');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const ontrackPromise = addEventListenerPromise(t, pc, 'track');
+ await pc.setRemoteDescription({type: 'offer',
+ sdp: preamble + 'a=msid:foo bar\n'});
+ const trackevent = await ontrackPromise;
+ assert_equals(pc.getReceivers().length, 1);
+ assert_equals(trackevent.streams.length, 1);
+ assert_equals(trackevent.streams[0].id, 'foo');
+}, 'Description with msid:foo bar produces a stream with id foo');
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const ontrackPromise = addEventListenerPromise(t, pc, 'track');
+ await pc.setRemoteDescription({type: 'offer',
+ sdp: preamble + 'a=msid:foo bar\n'
+ + 'a=msid:baz bar\n'});
+ const trackevent = await ontrackPromise;
+ assert_equals(pc.getReceivers().length, 1);
+ assert_equals(trackevent.streams.length, 2);
+}, 'Description with two msid produces two streams');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<!-- This file contains a test that waits for two seconds. -->
+<meta name="timeout" content="long">
+<title>RTP clockrate</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+async function initiateSingleTrackCallAndReturnReceiver(t, kind) {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({[kind]:true});
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+ pc1.addTrack(track, stream);
+
+ exchangeIceCandidates(pc1, pc2);
+ const trackEvent = await exchangeOfferAndListenToOntrack(t, pc1, pc2);
+ await exchangeAnswer(pc1, pc2);
+ await waitForConnectionStateChange(pc2, ['connected']);
+ return trackEvent.receiver;
+}
+
+promise_test(async t => {
+ // the getSynchronizationSources API exposes the rtp timestamp.
+ const receiver = await initiateSingleTrackCallAndReturnReceiver(t, 'video');
+ const warmUp = await listenForSSRCs(t, receiver);
+ await new Promise(resolve => t.step_timeout(resolve, 2000));
+ const first = await listenForSSRCs(t, receiver);
+ await new Promise(resolve => t.step_timeout(resolve, 2000));
+ const second = await listenForSSRCs(t, receiver);
+ // rtpTimestamp may wrap at 0xffffffff, take care of that.
+ const actualClockRate = ((second[0].rtpTimestamp - first[0].rtpTimestamp + 0xffffffff) % 0xffffffff) / (second[0].timestamp - first[0].timestamp) * 1000;
+ assert_approx_equals(actualClockRate, 90000, 9000, 'Video clockrate is approximately 90000');
+}, 'video rtp timestamps increase by approximately 90000 per second');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection payload type demuxing</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection({bundlePolicy: 'max-compat'});
+ t.add_cleanup(() => caller.close());
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ exchangeIceCandidates(caller, callee);
+
+ const stream = await getNoiseStream({video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => caller.addTrack(track, stream));
+ stream.getTracks().forEach(track => caller.addTrack(track.clone(), stream.clone()));
+
+ let callCount = 0;
+ let metadataToBeLoaded = new Promise(resolve => {
+ callee.ontrack = (e) => {
+ const stream = e.streams[0];
+ const v = document.createElement('video');
+ v.autoplay = true;
+ v.srcObject = stream;
+ v.id = stream.id
+ v.addEventListener('loadedmetadata', () => {
+ if (++callCount === 2) {
+ resolve();
+ }
+ });
+ };
+ });
+
+ const offer = await caller.createOffer();
+ // Replace BUNDLE, the mid header extension and all ssrc lines
+ // with bogus. The receiver will be forced to do payload type demuxing
+ // which is still possible because the different m-lines arrive on
+ // different ports/sockets.
+ const sdp = offer.sdp.replace('BUNDLE', 'SOMETHING')
+ .replace(/rtp-hdrext:sdes/g, 'rtp-hdrext:something')
+ .replace(/a=ssrc:/g, 'a=notssrc');
+
+ await callee.setRemoteDescription({type: 'offer', sdp});
+ await caller.setLocalDescription(offer);
+
+ const answer = await callee.createAnswer();
+ await caller.setRemoteDescription(answer);
+ await callee.setLocalDescription(answer);
+
+ await metadataToBeLoaded;
+}, 'Can demux two video tracks with the same payload type on an unbundled connection');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>payload type handling (assuming rtcp-mux)</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+// Tests behaviour from https://tools.ietf.org/html/rfc5761#section-4
+
+function createOfferSdp(opusPayloadType) {
+ return `v=0
+o=- 0 3 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
+a=ice-ufrag:6HHHdzzeIhkE0CKj
+a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew
+m=audio 9 RTP/SAVPF ${opusPayloadType}
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendonly
+a=mid:audio
+a=rtpmap:${opusPayloadType} opus/48000/2
+a=setup:actpass
+`;
+}
+
+promise_test(async t => {
+ for (let payloadType = 96; payloadType <= 127; payloadType++) {
+ const pc = new RTCPeerConnection();
+ await pc.setRemoteDescription({type: 'offer', sdp: createOfferSdp(payloadType)});
+ const answer = await pc.createAnswer();
+ assert_true(answer.sdp.includes(`a=rtpmap:${payloadType} opus/48000/2`));
+ pc.close();
+ }
+}, 'setRemoteDescription with a codec in the range 96-127 works');
+
+// This is written as a separate test since it currently fails in Chrome.
+promise_test(async t => {
+ for (let payloadType = 35; payloadType <= 63; payloadType++) {
+ const pc = new RTCPeerConnection();
+ await pc.setRemoteDescription({type: 'offer', sdp: createOfferSdp(payloadType)});
+ const answer = await pc.createAnswer();
+ assert_true(answer.sdp.includes(`a=rtpmap:${payloadType} opus/48000/2`));
+ pc.close();
+ }
+}, 'setRemoteDescription with a codec in the range 35-63 works');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTX codec integrity checks</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../third_party/sdp/sdp.js"></script>
+<script>
+'use strict';
+
+// Tests for conformance to rules for RTX codecs.
+// Basic rule: Offers and answers must contain RTX codecs, and the
+// RTX codecs must have an a=fmtp line that points to a non-RTX codec.
+
+// Helper function for doing one round of offer/answer exchange
+// between two local peer connections.
+// Calls setRemoteDescription(offer/answer) before
+// setLocalDescription(offer/answer) to ensure the remote description
+// is set and candidates can be added before the local peer connection
+// starts generating candidates and ICE checks.
+async function doSignalingHandshake(localPc, remotePc, options={}) {
+ let offer = await localPc.createOffer();
+ // Modify offer if callback has been provided
+ if (options.modifyOffer) {
+ offer = await options.modifyOffer(offer);
+ }
+
+ // Apply offer.
+ await remotePc.setRemoteDescription(offer);
+ await localPc.setLocalDescription(offer);
+
+ let answer = await remotePc.createAnswer();
+ // Modify answer if callback has been provided
+ if (options.modifyAnswer) {
+ answer = await options.modifyAnswer(answer);
+ }
+
+ // Apply answer.
+ await localPc.setRemoteDescription(answer);
+ await remotePc.setLocalDescription(answer);
+}
+
+function verifyRtxReferences(description) {
+ const mediaSection = SDPUtils.getMediaSections(description.sdp)[0];
+ const rtpParameters = SDPUtils.parseRtpParameters(mediaSection);
+ for (const codec of rtpParameters.codecs) {
+ if (codec.name === 'rtx') {
+ assert_own_property(codec.parameters, 'apt', 'rtx codec has apt parameter');
+ const referenced_codec = rtpParameters.codecs.find(
+ c => c.payloadType === parseInt(codec.parameters.apt));
+ assert_true(referenced_codec !== undefined, `Found referenced codec`);
+ }
+ }
+}
+
+
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const offer = await generateVideoReceiveOnlyOffer(pc);
+ verifyRtxReferences(offer);
+}, 'Initial offer should have sensible RTX mappings');
+
+async function negotiateAndReturnAnswer(t) {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+ let [track, streams] = await getTrackFromUserMedia('video');
+ const sender = pc1.addTrack(track);
+ await doSignalingHandshake(pc1, pc2);
+ return pc2.localDescription;
+}
+
+promise_test(async t => {
+ const answer = await negotiateAndReturnAnswer(t);
+ verifyRtxReferences(answer);
+}, 'Self-negotiated answer should have sensible RTX parameters');
+
+promise_test(async t => {
+ const sampleOffer = `v=0
+o=- 1878890426675213188 2 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE video
+a=msid-semantic: WMS
+m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99
+c=IN IP4 0.0.0.0
+a=rtcp:9 IN IP4 0.0.0.0
+a=ice-ufrag:RGPK
+a=ice-pwd:rAyHEAKC7ckxQgWaRZXukz+Z
+a=ice-options:trickle
+a=fingerprint:sha-256 8C:29:0A:8F:11:06:BF:1C:58:B3:CA:E6:F1:F1:DC:99:4C:6C:89:E9:FF:BC:D4:38:11:18:1F:40:19:C8:49:37
+a=setup:actpass
+a=mid:video
+a=recvonly
+a=rtcp-mux
+a=rtpmap:97 rtx/90000
+a=fmtp:97 apt=98
+a=rtpmap:98 VP8/90000
+a=rtcp-fb:98 ccm fir
+a=rtcp-fb:98 nack
+a=rtcp-fb:98 nack pli
+a=rtcp-fb:98 goog-remb
+a=rtcp-fb:98 transport-cc
+`;
+ const pc = new RTCPeerConnection();
+ let [track, streams] = await getTrackFromUserMedia('video');
+ const sender = pc.addTrack(track);
+ await pc.setRemoteDescription({type: 'offer', sdp: sampleOffer});
+ const answer = await pc.createAnswer();
+ verifyRtxReferences(answer);
+}, 'A remote offer generates sensible RTX references in answer');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerconnection SDP SCTP format test</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ t.add_cleanup(() => callee.close());
+ caller.createDataChannel('channel');
+ const offer = await caller.createOffer();
+ const [preamble, media_section, postamble] = offer.sdp.split('\r\nm=');
+ assert_true(typeof(postamble) === 'undefined');
+ assert_greater_than(media_section.search(
+ /^application \d+ UDP\/DTLS\/SCTP webrtc-datachannel\r\n/), -1);
+ assert_greater_than(media_section.search(/\r\na=sctp-port:\d+\r\n/), -1);
+ assert_greater_than(media_section.search(/\r\na=mid:/), -1);
+}, 'Generated Datachannel SDP uses correct SCTP offer syntax');
+
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title>RTCPeerConnection MUST NOT support SDES</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../third_party/sdp/sdp.js"></script>
+<script>
+'use strict';
+
+// Test support for
+// https://www.rfc-editor.org/rfc/rfc8826#section-4.3.1
+
+const sdp = `v=0
+o=- 0 3 IN IP4 127.0.0.1
+s=-
+t=0 0
+m=video 9 UDP/TLS/RTP/SAVPF 100
+c=IN IP4 0.0.0.0
+a=rtcp-mux
+a=sendonly
+a=mid:video
+a=rtpmap:100 VP8/90000
+a=fmtp:100 max-fr=30;max-fs=3600
+a=crypto:0 AES_CM_128_HMAC_SHA1_80 inline:2nra27hTUb9ilyn2rEkBEQN9WOFts26F/jvofasw
+a=ice-ufrag:ETEn
+a=ice-pwd:OtSK0WpNtpUjkY4+86js7Z/l
+`;
+
+// Negative test for Chrome legacy behavior.
+/*
+promise_test(async t => {
+ const sdes_constraint = {'mandatory': {'DtlsSrtpKeyAgreement': false}};
+ const pc = new RTCPeerConnection(null, sdes_constraint);
+ t.add_cleanup(() => pc.close());
+
+ pc.addTransceiver('audio');
+ const offer = await pc.createOffer();
+ assert_false(offer.sdp.includes('\na=crypto:'));
+}, 'does not create offers with SDES');
+*/
+
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+
+ try {
+ await pc.setRemoteDescription({type: 'offer', sdp});
+ assert_unreached("Must not accept SDP without fingerprint");
+ } catch (e) {
+ // TODO: which error is correct? See
+ // https://github.com/w3c/webrtc-pc/issues/2672
+ assert_true(['OperationError', 'InvalidAccessError'].includes(e.name));
+ }
+}, 'rejects a remote offer that only includes SDES and no DTLS fingerprint');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Answer</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+// Tests for the construction of answers with simulcast according to:
+// draft-ietf-mmusic-sdp-simulcast-13
+// draft-ietf-mmusic-rid-15
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const expected_rids = ['foo', 'bar', 'baz'];
+
+ const offer_sdp = `v=0
+o=- 3840232462471583827 2 IN IP4 127.0.0.1
+s=-
+t=0 0
+a=group:BUNDLE 0
+a=msid-semantic: WMS
+m=video 9 UDP/TLS/RTP/SAVPF 96
+c=IN IP4 0.0.0.0
+a=rtcp:9 IN IP4 0.0.0.0
+a=ice-ufrag:Li6+
+a=ice-pwd:3C05CTZBRQVmGCAq7hVasHlT
+a=ice-options:trickle
+a=fingerprint:sha-256 5B:D3:8E:66:0E:7D:D3:F3:8E:E6:80:28:19:FC:55:AD:58:5D:B9:3D:A8:DE:45:4A:E7:87:02:F8:3C:0B:3B:B3
+a=setup:actpass
+a=mid:0
+a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id
+a=recvonly
+a=rtcp-mux
+a=rtpmap:96 VP8/90000
+a=rtcp-fb:96 goog-remb
+a=rtcp-fb:96 transport-cc
+a=rtcp-fb:96 ccm fir
+a=rid:foo recv
+a=rid:bar recv
+a=rid:baz recv
+a=simulcast:recv foo;bar;baz
+`;
+
+ await pc.setRemoteDescription({type: 'offer', sdp: offer_sdp});
+ const transceiver = pc.getTransceivers()[0];
+ // The created transceiver should be in "recvonly" state. Allow it to send.
+ transceiver.direction = "sendonly";
+ const answer = await pc.createAnswer();
+ let answer_lines = answer.sdp.split('\r\n');
+ // Check for a RID line for each layer.
+ for (const rid of expected_rids) {
+ let result = answer_lines.find(line => line.startsWith(`a=rid:${rid}`));
+ assert_not_equals(result, undefined, `RID attribute for '${rid}' missing.`);
+ }
+
+ // Check for simulcast attribute with send direction and all RIDs.
+ let result = answer_lines.find(
+ line => line.startsWith(`a=simulcast:send ${expected_rids.join(';')}`));
+ assert_not_equals(result, undefined, "Could not find simulcast attribute.");
+}, 'createAnswer() with multiple send encodings should create simulcast answer');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Offer</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+// Tests for the construction of offers with simulcast according to:
+// draft-ietf-mmusic-sdp-simulcast-13
+// draft-ietf-mmusic-rid-15
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const expected_rids = ['foo', 'bar', 'baz'];
+ pc.addTransceiver('video', {
+ sendEncodings: expected_rids.map(rid => ({rid}))
+ });
+
+ const offer = await pc.createOffer();
+ let offer_lines = offer.sdp.split('\r\n');
+ // Check for a RID line for each layer.
+ for (const rid of expected_rids) {
+ let result = offer_lines.find(line => line.startsWith(`a=rid:${rid}`));
+ assert_not_equals(result, undefined, `RID attribute for '${rid}' missing.`);
+ }
+
+ // Check for simulcast attribute with send direction and all RIDs.
+ let result = offer_lines.find(
+ line => line.startsWith(`a=simulcast:send ${expected_rids.join(';')}`));
+ assert_not_equals(result, undefined, "Could not find simulcast attribute.");
+}, 'createOffer() with multiple send encodings should create simulcast offer');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection BUNDLE</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../third_party/sdp/sdp.js"></script>
+<script>
+'use strict';
+promise_test(async t => {
+ const caller = new RTCPeerConnection();
+ t.add_cleanup(() => caller.close());
+ const calleeAudio = new RTCPeerConnection();
+ t.add_cleanup(() => calleeAudio.close());
+ const calleeVideo = new RTCPeerConnection();
+ t.add_cleanup(() => calleeVideo.close());
+
+ const stream = await getNoiseStream({audio: true, video: true});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ stream.getTracks().forEach(track => caller.addTrack(track, stream));
+
+ let metadataToBeLoaded;
+ calleeVideo.ontrack = (e) => {
+ const stream = e.streams[0];
+ const v = document.createElement('video');
+ v.autoplay = true;
+ v.srcObject = stream;
+ v.id = stream.id
+ metadataToBeLoaded = new Promise((resolve) => {
+ v.addEventListener('loadedmetadata', () => {
+ resolve();
+ });
+ });
+ };
+
+ caller.addEventListener('icecandidate', (e) => {
+ // route depending on sdpMlineIndex
+ if (e.candidate) {
+ const target = e.candidate.sdpMLineIndex === 0 ? calleeAudio : calleeVideo;
+ target.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
+ } else {
+ calleeAudio.addIceCandidate();
+ calleeVideo.addIceCandidate();
+ }
+ });
+ calleeAudio.addEventListener('icecandidate', (e) => {
+ if (e.candidate) {
+ caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
+ }
+ // Note: caller.addIceCandidate is only called for video to avoid calling it twice.
+ });
+ calleeVideo.addEventListener('icecandidate', (e) => {
+ if (e.candidate) {
+ caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
+ } else {
+ caller.addIceCandidate();
+ }
+ });
+
+ const offer = await caller.createOffer();
+ const sections = SDPUtils.splitSections(offer.sdp);
+ // Remove the a=group:BUNDLE from the SDP when signaling.
+ const bundle = SDPUtils.matchPrefix(sections[0], 'a=group:BUNDLE')[0];
+ sections[0] = sections[0].replace(bundle + '\r\n', '');
+
+ const audioSdp = sections[0] + sections[1];
+ const videoSdp = sections[0] + sections[2];
+
+ await calleeAudio.setRemoteDescription({type: 'offer', sdp: audioSdp});
+ await calleeVideo.setRemoteDescription({type: 'offer', sdp: videoSdp});
+ await caller.setLocalDescription(offer);
+
+ const answerAudio = await calleeAudio.createAnswer();
+ const answerVideo = await calleeVideo.createAnswer();
+ const audioSections = SDPUtils.splitSections(answerAudio.sdp);
+ const videoSections = SDPUtils.splitSections(answerVideo.sdp);
+
+ // Remove the fingerprint from the session part of the SDP if present
+ // and move it to the media section.
+ SDPUtils.matchPrefix(audioSections[0], 'a=fingerprint:').forEach(line => {
+ audioSections[0] = audioSections[0].replace(line + '\r\n', '');
+ audioSections[1] += line + '\r\n';
+ });
+ SDPUtils.matchPrefix(videoSections[0], 'a=fingerprint:').forEach(line => {
+ videoSections[0] = videoSections[0].replace(line + '\r\n', '');
+ videoSections[1] += line + '\r\n';
+ });
+
+ const sdp = audioSections[0] + audioSections[1] + videoSections[1];
+ await caller.setRemoteDescription({type: 'answer', sdp});
+ await calleeAudio.setLocalDescription(answerAudio);
+ await calleeVideo.setLocalDescription(answerVideo);
+
+ await metadataToBeLoaded;
+ assert_equals(calleeAudio.connectionState, 'connected');
+ assert_equals(calleeVideo.connectionState, 'connected');
+}, 'Connect audio and video to two independent PeerConnections');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerconnection SDP handling of unknown media types</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ t.add_cleanup(() => pc2.close());
+
+ const stream = await getNoiseStream({audio: true});
+ pc1.addTrack(stream.getTracks()[0], stream);
+ const offer = await pc1.createOffer();
+ await pc2.setRemoteDescription({
+ type: 'offer',
+ sdp: offer.sdp
+ .replace('m=audio ', 'm=unicorns ')
+ });
+ await pc1.setLocalDescription(offer);
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ // Do not attempt to call pc1.setRemoteDescription.
+
+ const [preamble, media_section, postamble] = answer.sdp.split('\r\nm=');
+ assert_true(typeof(postamble) === 'undefined');
+ assert_greater_than(media_section.search(
+ /^unicorns 0/), -1);
+}, 'Unknown media types are rejected with the port set to 0');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection.prototype.createOffer</title>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script>
+'use strict';
+
+/*
+ * Chromium note: this requires build bots with H264 support. See
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
+ * for details on how to enable support.
+ */
+// Tests for conformance to RFC 7742,
+// "WebRTC Video Processing and Codec Requirements"
+// The document was formerly known as draft-ietf-rtcweb-video-codecs.
+//
+// This tests that the browser is a WebRTC Browser as defined there.
+
+// TODO: Section 3.2: screen capture video MUST be prepared
+// to handle resolution changes.
+
+// TODO: Section 4: MUST support generating CVO (orientation)
+
+// Section 5: Browsers MUST implement VP8 and H.264 Constrained Baseline
+promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const offer = await generateVideoReceiveOnlyOffer(pc);
+ let video_section_found = false;
+ for (let section of offer.sdp.split(/\r\nm=/)) {
+ if (section.search('video') != 0) {
+ continue;
+ }
+ video_section_found = true;
+ // RTPMAP lines have the format a=rtpmap:<pt> <codec>/<clock rate>
+ let rtpmap_regex = /\r\na=rtpmap:(\d+) (\S+)\/\d+\r\n/g;
+ let match = rtpmap_regex.exec(offer.sdp);
+ let payload_type_map = new Array();
+ while (match) {
+ payload_type_map[match[1]] = match[2];
+ match = rtpmap_regex.exec(offer.sdp);
+ }
+ assert_true(payload_type_map.indexOf('VP8') > -1,
+ 'VP8 is supported');
+ assert_true(payload_type_map.indexOf('H264') > -1,
+ 'H.264 is supported');
+ // TODO: Verify that one of the H.264 PTs supports constrained baseline
+ }
+ assert_true(video_section_found);
+}, 'H.264 and VP8 should be supported in initial offer');
+
+async function negotiateParameters() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+ let [track, streams] = await getTrackFromUserMedia('video');
+ const sender = pc1.addTrack(track);
+ await exchangeOfferAnswer(pc1, pc2);
+ return sender.getParameters();
+}
+
+function parseFmtp(fmtp) {
+ const params = fmtp.split(';');
+ return params.map(param => param.split('='));
+}
+promise_test(async t => {
+ const params = await negotiateParameters();
+ assert_true(!!params.codecs.find(codec => codec.mimeType === 'video/H264'));
+ assert_true(!!params.codecs.find(codec => codec.mimeType === 'video/VP8'));
+}, 'H.264 and VP8 should be negotiated after handshake');
+
+// TODO: Section 6: Recipients MUST be able to decode 320x240@20 fps
+// TODO: Section 6.1: VP8 MUST support RFC 7741 payload formats
+// TODO: Section 6.1: VP8 MUST respect max-fr/max-fs
+// TODO: Section 6.1: VP8 MUST encode and decode square pixels
+// TODO: Section 6.2: H.264 MUST support RFC 6184 payload formats
+// TODO: Section 6.2: MUST support Constrained Baseline level 1.2
+// TODO: Section 6.2: SHOULD support Constrained High level 1.3
+// TODO: Section 6.2: MUST support packetization mode 1.
+promise_test(async t => {
+ const params = await negotiateParameters();
+ const h264 = params.codecs.filter(codec => codec.mimeType === 'video/H264');
+ h264.map(codec => {
+ const codec_params = parseFmtp(codec.sdpFmtpLine);
+ assert_true(!!codec_params.find(x => x[0] === 'profile-level-id'));
+ })
+}, 'All H.264 codecs MUST include profile-level-id');
+
+// TODO: Section 6.2: SHOULD interpret max-mbps, max-smbps, max-fs et al
+// TODO: Section 6.2: MUST NOT include sprop-parameter-sets
+// TODO: Section 6.2: MUST support SEI "filler payload"
+// TODO: Section 6.2: MUST support SEI "full frame freeze"
+// TODO: Section 6.2: MUST be prepared to receive User Data messages
+// TODO: Section 6.2: MUST encode and decode square pixels unless signaled
+</script>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Remote tracks should not get ended except for stop/close</title>
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script src="../../resources/testdriver.js"></script>
+ <script src="../../resources/testdriver-vendor.js"></script>
+ <script src="support/permission-helper.js"></script>
+ <script src="support/RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+ <video id="video" controls autoplay playsinline></video>
+ <script>
+ let pc1, pc2;
+ let localTrack, remoteTrack;
+ promise_test(async (test) => {
+ await setMediaPermission("granted", ["microphone"]);
+ const localStream = await navigator.mediaDevices.getUserMedia({audio: true});
+ localTrack = localStream.getAudioTracks()[0];
+
+ pc1 = new RTCPeerConnection();
+ pc1.addTrack(localTrack, localStream);
+ pc2 = new RTCPeerConnection();
+
+ let trackPromise = new Promise(resolve => {
+ pc2.ontrack = e => resolve(e.track);
+ });
+
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+
+ remoteTrack = await trackPromise;
+ video.srcObject = new MediaStream([remoteTrack]);
+ await video.play();
+ }, "Setup audio call");
+
+ promise_test(async (test) => {
+ pc1.getTransceivers()[0].direction = "inactive";
+
+ let offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer);
+
+ // Let's remove ssrc lines
+ let sdpLines = offer.sdp.split("\r\n");
+ offer.sdp = sdpLines.filter(line => line && !line.startsWith("a=ssrc")).join("\r\n") + "\r\n";
+
+ await pc2.setRemoteDescription(offer);
+ let answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription(answer);
+
+ assert_equals(remoteTrack.readyState, "live");
+ }, "Inactivate the audio transceiver");
+
+ promise_test(async (test) => {
+ pc1.getTransceivers()[0].direction = "sendonly";
+
+ await exchangeOfferAnswer(pc1, pc2);
+
+ assert_equals(remoteTrack.readyState, "live");
+ }, "Reactivate the audio transceiver");
+
+ promise_test(async (test) => {
+ pc1.close();
+ pc2.close();
+ localTrack.stop();
+ }, "Clean-up");
+ </script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const audioTransceiver = pc1.addTransceiver('audio', {direction:'recvonly'});
+
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ audioTransceiver.direction = 'sendrecv';
+
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+}, '[audio] recvonly transceiver can become sendrecv');
+
+promise_test(async t => {
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ const videoTransceiver = pc1.addTransceiver('video', {direction:'recvonly'});
+
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ videoTransceiver.direction = 'sendrecv';
+
+ await pc1.setLocalDescription();
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+}, '[video] recvonly transceiver can become sendrecv');
+
+</script>
--- /dev/null
+<!doctype html>
+<script>
+window.onmessage = async (event) => {
+ let certificate = event.data;
+ if (!certificate)
+ certificate = await RTCPeerConnection.generateCertificate({ name: 'ECDSA', namedCurve: 'P-256'});
+ event.source.postMessage(certificate, "*");
+}
+</script>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection Connection Test</title>
+ <script src="support/RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <div>
+ <video id="local-view" muted autoplay="autoplay"></video>
+ <video id="remote-view" muted autoplay="autoplay"/>
+ </video>
+ </div>
+
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script type="text/javascript">
+ var test = async_test('Can set up a basic WebRTC call without announcing ssrcs.');
+
+ var gFirstConnection = null;
+ var gSecondConnection = null;
+
+ // if the remote video gets video data that implies the negotiation
+ // as well as the ICE and DTLS connection are up.
+ document.getElementById('remote-view')
+ .addEventListener('loadedmetadata', function() {
+ // Call negotiated: done.
+ test.done();
+ });
+
+ function getNoiseStreamOkCallback(localStream) {
+ gFirstConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gFirstConnection.close());
+ gFirstConnection.onicecandidate = onIceCandidateToFirst;
+ localStream.getTracks().forEach(function(track) {
+ gFirstConnection.addTrack(track, localStream);
+ });
+ gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
+
+ var videoTag = document.getElementById('local-view');
+ videoTag.srcObject = localStream;
+ };
+
+ var onOfferCreated = test.step_func(function(offer) {
+ gFirstConnection.setLocalDescription(offer);
+
+ // remove all a=ssrc: lines and the (obsolete) msid-semantic line.
+ var sdp = offer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
+ .replace(/^a=msid-semantic.*$\r\n/gm, '');
+
+ // This would normally go across the application's signaling solution.
+ // In our case, the "signaling" is to call this function.
+ receiveCall(sdp);
+ });
+
+ function receiveCall(offerSdp) {
+ gSecondConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gSecondConnection.close());
+ gSecondConnection.onicecandidate = onIceCandidateToSecond;
+ gSecondConnection.ontrack = onRemoteTrack;
+
+ var parsedOffer = new RTCSessionDescription({ type: 'offer',
+ sdp: offerSdp });
+ gSecondConnection.setRemoteDescription(parsedOffer);
+
+ gSecondConnection.createAnswer().then(onAnswerCreated,
+ failed('createAnswer'));
+ };
+
+ var onAnswerCreated = test.step_func(function(answer) {
+ gSecondConnection.setLocalDescription(answer);
+
+ // remove all a=ssrc: lines, the msid-semantic line and any a=msid:.
+ var sdp = answer.sdp.replace(/^a=ssrc:.*$\r\n/gm, '')
+ .replace(/^a=msid-semantic.*$\r\n/gm, '')
+ .replace(/^a=msid:.*$\r\n/gm, '');
+
+ // Similarly, this would go over the application's signaling solution.
+ handleAnswer(sdp);
+ });
+
+ function handleAnswer(answerSdp) {
+ var parsedAnswer = new RTCSessionDescription({ type: 'answer',
+ sdp: answerSdp });
+ gFirstConnection.setRemoteDescription(parsedAnswer);
+ };
+
+ var onIceCandidateToFirst = test.step_func(function(event) {
+ gSecondConnection.addIceCandidate(event.candidate);
+ });
+
+ var onIceCandidateToSecond = test.step_func(function(event) {
+ gFirstConnection.addIceCandidate(event.candidate);
+ });
+
+ var onRemoteTrack = test.step_func(function(event) {
+ var videoTag = document.getElementById('remote-view');
+ if (!videoTag.srcObject) {
+ videoTag.srcObject = event.streams[0];
+ }
+ });
+
+ // Returns a suitable error callback.
+ function failed(function_name) {
+ return test.unreached_func('WebRTC called error callback for ' + function_name);
+ }
+
+ // This function starts the test.
+ test.step(function() {
+ getNoiseStream({ video: true, audio: true })
+ .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
+ });
+</script>
+
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>RTCPeerConnection Connection Test</title>
+ <script src="support/RTCPeerConnection-helper.js"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <div>
+ <video id="local-view" muted autoplay="autoplay"></video>
+ <video id="remote-view" muted autoplay="autoplay"/>
+ </video>
+ </div>
+
+ <!-- These files are in place when executing on W3C. -->
+ <script src="../../resources/testharness.js"></script>
+ <script src="../../resources/testharnessreport.js"></script>
+ <script type="text/javascript">
+ var test = async_test('Can set up a basic WebRTC call.');
+
+ var gFirstConnection = null;
+ var gSecondConnection = null;
+
+ // if the remote video gets video data that implies the negotiation
+ // as well as the ICE and DTLS connection are up.
+ document.getElementById('remote-view')
+ .addEventListener('loadedmetadata', function() {
+ // Call negotiated: done.
+ test.done();
+ });
+
+ function getNoiseStreamOkCallback(localStream) {
+ gFirstConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gFirstConnection.close());
+ gFirstConnection.onicecandidate = onIceCandidateToFirst;
+ localStream.getTracks().forEach(function(track) {
+ gFirstConnection.addTrack(track, localStream);
+ });
+ gFirstConnection.createOffer().then(onOfferCreated, failed('createOffer'));
+
+ var videoTag = document.getElementById('local-view');
+ videoTag.srcObject = localStream;
+ };
+
+ var onOfferCreated = test.step_func(function(offer) {
+ gFirstConnection.setLocalDescription(offer);
+
+ // This would normally go across the application's signaling solution.
+ // In our case, the "signaling" is to call this function.
+ receiveCall(offer.sdp);
+ });
+
+ function receiveCall(offerSdp) {
+ gSecondConnection = new RTCPeerConnection(null);
+ test.add_cleanup(() => gSecondConnection.close());
+ gSecondConnection.onicecandidate = onIceCandidateToSecond;
+ gSecondConnection.ontrack = onRemoteTrack;
+
+ var parsedOffer = new RTCSessionDescription({ type: 'offer',
+ sdp: offerSdp });
+ gSecondConnection.setRemoteDescription(parsedOffer);
+
+ gSecondConnection.createAnswer().then(onAnswerCreated,
+ failed('createAnswer'));
+ };
+
+ var onAnswerCreated = test.step_func(function(answer) {
+ gSecondConnection.setLocalDescription(answer);
+
+ // Similarly, this would go over the application's signaling solution.
+ handleAnswer(answer.sdp);
+ });
+
+ function handleAnswer(answerSdp) {
+ var parsedAnswer = new RTCSessionDescription({ type: 'answer',
+ sdp: answerSdp });
+ gFirstConnection.setRemoteDescription(parsedAnswer);
+ };
+
+ var onIceCandidateToFirst = test.step_func(function(event) {
+ gSecondConnection.addIceCandidate(event.candidate);
+ });
+
+ var onIceCandidateToSecond = test.step_func(function(event) {
+ gFirstConnection.addIceCandidate(event.candidate);
+ });
+
+ var onRemoteTrack = test.step_func(function(event) {
+ var videoTag = document.getElementById('remote-view');
+ if (!videoTag.srcObject) {
+ videoTag.srcObject = event.streams[0];
+ }
+ });
+
+ // Returns a suitable error callback.
+ function failed(function_name) {
+ return test.unreached_func('WebRTC called error callback for ' + function_name);
+ }
+
+ // This function starts the test.
+ test.step(function() {
+ getNoiseStream({ video: true, audio: true })
+ .then(test.step_func(getNoiseStreamOkCallback), failed('getNoiseStream'));
+ });
+</script>
+
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Tests</title>
+<meta name="timeout" content="long">
+<script src="../third_party/sdp/sdp.js"></script>
+<script src="simulcast.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+promise_test(async t => {
+ const rids = [0, 1];
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
+}, 'Basic simulcast setup with two spatial layers');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Tests - getStats</title>
+<meta name="timeout" content="long">
+<script src="../third_party/sdp/sdp.js"></script>
+<script src="simulcast.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+promise_test(async t => {
+ const rids = [0, 1, 2];
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ await negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
+
+ const outboundStats = [];
+ const senderStats = await pc1.getSenders()[0].getStats();
+ senderStats.forEach(stat => {
+ if (stat.type === 'outbound-rtp') {
+ outboundStats.push(stat);
+ }
+ });
+ assert_equals(outboundStats.length, 3, "getStats result should contain three layers");
+ const statsRids = outboundStats.map(stat => parseInt(stat.rid, 10));
+ assert_array_equals(rids, statsRids.sort(), "getStats result should match the rids provided");
+}, 'Simulcast getStats results');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Tests</title>
+<meta name="timeout" content="long">
+<script src="../third_party/sdp/sdp.js"></script>
+<script src="simulcast.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+/*
+ * Chromium note: this requires build bots with H264 support. See
+ * https://bugs.chromium.org/p/chromium/issues/detail?id=840659
+ * for details on how to enable support.
+ */
+promise_test(async t => {
+ assert_implements('getCapabilities' in RTCRtpSender, 'RTCRtpSender.getCapabilities not supported');
+ assert_implements(RTCRtpSender.getCapabilities('video').codecs.find(c => c.mimeType === 'video/H264'), 'H264 not supported');
+
+ const rids = [0, 1];
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, {mimeType: 'video/H264'});
+}, 'H264 simulcast setup with two spatial layers');
+</script>
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Tests - setParameters/active</title>
+<meta name="timeout" content="long">
+<script src="../third_party/sdp/sdp.js"></script>
+<script src="simulcast.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+async function queryReceiverStats(pc) {
+ const inboundStats = [];
+ await Promise.all(pc.getReceivers().map(async receiver => {
+ const receiverStats = await receiver.getStats();
+ receiverStats.forEach(stat => {
+ if (stat.type === 'inbound-rtp') {
+ inboundStats.push(stat);
+ }
+ });
+ }));
+ return inboundStats.map(s => s.framesDecoded);
+}
+
+promise_test(async t => {
+ const rids = [0, 1];
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ await negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2);
+
+ // Deactivate all senders.
+ const parameters = pc1.getSenders()[0].getParameters();
+ parameters.encodings.forEach(e => {
+ e.active = false;
+ });
+ await pc1.getSenders()[0].setParameters(parameters);
+
+ // Assert (almost) no new frames are received.
+ // Without any action we would expect to have received around 30fps.
+ await new Promise(resolve => t.step_timeout(resolve, 100)); // Wait a bit.
+ const initialStats = await queryReceiverStats(pc2);
+ await new Promise(resolve => t.step_timeout(resolve, 1000)); // Wait more.
+ const subsequentStats = await queryReceiverStats(pc2);
+
+ subsequentStats.forEach((framesDecoded, idx) => {
+ assert_equals(framesDecoded, initialStats[idx]);
+ });
+}, 'Simulcast setParameters active=false stops sending frames');
+</script>
--- /dev/null
+'use strict';
+/* Helper functions to munge SDP and split the sending track into
+ * separate tracks on the receiving end. This can be done in a number
+ * of ways, the one used here uses the fact that the MID and RID header
+ * extensions which are used for packet routing share the same wire
+ * format. The receiver interprets the rids from the sender as mids
+ * which allows receiving the different spatial resolutions on separate
+ * m-lines and tracks.
+ */
+const extensionsToFilter = [
+ 'urn:ietf:params:rtp-hdrext:sdes:mid',
+ 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id',
+ 'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id',
+];
+
+function swapRidAndMidExtensionsInSimulcastOffer(offer, rids) {
+ const sections = SDPUtils.splitSections(offer.sdp);
+ const dtls = SDPUtils.getDtlsParameters(sections[1], sections[0]);
+ const ice = SDPUtils.getIceParameters(sections[1], sections[0]);
+ const rtpParameters = SDPUtils.parseRtpParameters(sections[1]);
+
+ // The gist of this hack is that rid and mid have the same wire format.
+ const rid = rtpParameters.headerExtensions.find(ext => ext.uri === 'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id');
+ rtpParameters.headerExtensions = rtpParameters.headerExtensions.filter(ext => {
+ return !extensionsToFilter.includes(ext.uri);
+ });
+ // This tells the other side that the RID packets are actually mids.
+ rtpParameters.headerExtensions.push({id: rid.id, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid', direction: 'sendrecv'});
+
+ // Filter rtx as we have no way to (re)interpret rrid.
+ // Not doing this makes probing use RTX, it's not understood and ramp-up is slower.
+ rtpParameters.codecs = rtpParameters.codecs.filter(c => c.name.toUpperCase() !== 'RTX');
+
+ let sdp = SDPUtils.writeSessionBoilerplate() +
+ SDPUtils.writeDtlsParameters(dtls, 'actpass') +
+ SDPUtils.writeIceParameters(ice) +
+ 'a=group:BUNDLE ' + rids.join(' ') + '\r\n';
+ const baseRtpDescription = SDPUtils.writeRtpDescription('video', rtpParameters);
+ rids.forEach(rid => {
+ sdp += baseRtpDescription +
+ 'a=mid:' + rid + '\r\n' +
+ 'a=msid:rid-' + rid + ' rid-' + rid + '\r\n';
+ });
+ return sdp;
+}
+
+function swapRidAndMidExtensionsInSimulcastAnswer(answer, localDescription, rids) {
+ const sections = SDPUtils.splitSections(answer.sdp);
+ const dtls = SDPUtils.getDtlsParameters(sections[1], sections[0]);
+ const ice = SDPUtils.getIceParameters(sections[1], sections[0]);
+ const rtpParameters = SDPUtils.parseRtpParameters(sections[1]);
+
+ rtpParameters.headerExtensions = rtpParameters.headerExtensions.filter(ext => {
+ return !extensionsToFilter.includes(ext.uri);
+ });
+ const localMid = SDPUtils.getMid(SDPUtils.splitSections(localDescription.sdp)[1]);
+ let sdp = SDPUtils.writeSessionBoilerplate() +
+ SDPUtils.writeDtlsParameters(dtls, 'active') +
+ SDPUtils.writeIceParameters(ice) +
+ 'a=group:BUNDLE ' + localMid + '\r\n';
+ sdp += SDPUtils.writeRtpDescription('video', rtpParameters);
+ sdp += 'a=mid:' + localMid + '\r\n';
+
+ rids.forEach(rid => {
+ sdp += 'a=rid:' + rid + ' recv\r\n';
+ });
+ sdp += 'a=simulcast:recv ' + rids.join(';') + '\r\n';
+
+ // Re-add headerextensions we filtered.
+ const headerExtensions = SDPUtils.parseRtpParameters(SDPUtils.splitSections(localDescription.sdp)[1]).headerExtensions;
+ headerExtensions.forEach(ext => {
+ if (extensionsToFilter.includes(ext.uri)) {
+ sdp += 'a=extmap:' + ext.id + ' ' + ext.uri + '\r\n';
+ }
+ });
+ return sdp;
+}
+
+async function negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, codec) {
+ exchangeIceCandidates(pc1, pc2);
+
+ const metadataToBeLoaded = [];
+ pc2.ontrack = (e) => {
+ const stream = e.streams[0];
+ const v = document.createElement('video');
+ v.autoplay = true;
+ v.srcObject = stream;
+ v.id = stream.id
+ metadataToBeLoaded.push(new Promise((resolve) => {
+ v.addEventListener('loadedmetadata', () => {
+ resolve();
+ });
+ }));
+ };
+
+ const sendEncodings = rids.map(rid => ({rid}));
+ // Use a 2X downscale factor between each layer. To improve ramp-up time, the
+ // top layer is scaled down by a factor 2. Smaller layer comes first. For
+ // example if MediaStreamTrack is 720p and we want to send three layers we'll
+ // get {90p, 180p, 360p}.
+ let scaleResolutionDownBy = 2;
+ for (let i = sendEncodings.length - 1; i >= 0; --i) {
+ sendEncodings[i].scaleResolutionDownBy = scaleResolutionDownBy;
+ scaleResolutionDownBy *= 2;
+ }
+ // Use getUserMedia as getNoiseStream does not have enough entropy to ramp-up.
+ await setMediaPermission();
+ const stream = await navigator.mediaDevices.getUserMedia({video: {width: 1280, height: 720}});
+ t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
+ const transceiver = pc1.addTransceiver(stream.getVideoTracks()[0], {
+ streams: [stream],
+ sendEncodings: sendEncodings,
+ });
+ if (codec) {
+ preferCodec(transceiver, codec.mimeType, codec.sdpFmtpLine);
+ }
+ const offer = await pc1.createOffer();
+ await pc1.setLocalDescription(offer),
+ await pc2.setRemoteDescription({
+ type: 'offer',
+ sdp: swapRidAndMidExtensionsInSimulcastOffer(offer, rids),
+ });
+ const answer = await pc2.createAnswer();
+ await pc2.setLocalDescription(answer);
+ await pc1.setRemoteDescription({
+ type: 'answer',
+ sdp: swapRidAndMidExtensionsInSimulcastAnswer(answer, pc1.localDescription, rids),
+ });
+ assert_equals(metadataToBeLoaded.length, rids.length);
+ return Promise.all(metadataToBeLoaded);
+}
--- /dev/null
+<!doctype html>
+<meta charset=utf-8>
+<title>RTCPeerConnection Simulcast Tests</title>
+<meta name="timeout" content="long">
+<script src="../third_party/sdp/sdp.js"></script>
+<script src="simulcast.js"></script>
+<script src="../support/RTCPeerConnection-helper.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<script src="../../../resources/testdriver.js"></script>
+<script src="../../../resources/testdriver-vendor.js"></script>
+<script src="../support/permission-helper.js"></script>
+<script>
+promise_test(async t => {
+ assert_implements('getCapabilities' in RTCRtpSender, 'RTCRtpSender.getCapabilities not supported');
+ assert_implements(RTCRtpSender.getCapabilities('video').codecs.find(c => c.mimeType === 'video/VP8'), 'VP8 not supported');
+
+ const rids = [0, 1];
+ const pc1 = new RTCPeerConnection();
+ t.add_cleanup(() => pc1.close());
+ const pc2 = new RTCPeerConnection();
+ t.add_cleanup(() => pc2.close());
+
+ return negotiateSimulcastAndWaitForVideo(t, rids, pc1, pc2, {mimeType: 'video/VP8'});
+}, 'VP8 simulcast setup with two spatial layers');
+</script>
--- /dev/null
+'use strict';
+
+// Run a test function as two test cases.
+// The first test case test the configuration by passing a given config
+// to the constructor.
+// The second test case create an RTCPeerConnection object with default
+// configuration, then call setConfiguration with the provided config.
+// The test function is given a constructor function to create
+// a new instance of RTCPeerConnection with given config,
+// either directly as constructor parameter or through setConfiguration.
+function config_test(test_func, desc) {
+ test(() => {
+ test_func(config => new RTCPeerConnection(config));
+ }, `new RTCPeerConnection(config) - ${desc}`);
+
+ test(() => {
+ test_func(config => {
+ const pc = new RTCPeerConnection();
+ assert_idl_attribute(pc, 'setConfiguration');
+ pc.setConfiguration(config);
+ return pc;
+ })
+ }, `setConfiguration(config) - ${desc}`);
+}
--- /dev/null
+'use strict';
+
+// Test is based on the following editor draft:
+// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+// Code using this helper should also include RTCPeerConnection-helper.js
+// in the main HTML file
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// getTrackFromUserMedia
+// exchangeOfferAnswer
+
+// Create a RTCDTMFSender using getUserMedia()
+// Connect the PeerConnection to another PC and wait until it is
+// properly connected, so that DTMF can be sent.
+function createDtmfSender(pc = new RTCPeerConnection()) {
+ let dtmfSender;
+ return getTrackFromUserMedia('audio')
+ .then(([track, mediaStream]) => {
+ const sender = pc.addTrack(track, mediaStream);
+ dtmfSender = sender.dtmf;
+ assert_true(dtmfSender instanceof RTCDTMFSender,
+ 'Expect audio sender.dtmf to be set to a RTCDTMFSender');
+ // Note: spec bug open - https://github.com/w3c/webrtc-pc/issues/1774
+ // on whether sending should be possible before negotiation.
+ const pc2 = new RTCPeerConnection();
+ Object.defineProperty(pc, 'otherPc', { value: pc2 });
+ exchangeIceCandidates(pc, pc2);
+ return exchangeOfferAnswer(pc, pc2);
+ }).then(() => {
+ if (!('canInsertDTMF' in dtmfSender)) {
+ return Promise.resolve();
+ }
+ // Wait until dtmfSender.canInsertDTMF becomes true.
+ // Up to 150 ms has been observed in test. Wait 1 second
+ // in steps of 10 ms.
+ // Note: Using a short timeout and rejected promise in order to
+ // make test return a clear error message on failure.
+ return new Promise((resolve, reject) => {
+ let counter = 0;
+ step_timeout(function checkCanInsertDTMF() {
+ if (dtmfSender.canInsertDTMF) {
+ resolve();
+ } else {
+ if (counter >= 100) {
+ reject('Waited too long for canInsertDTMF');
+ return;
+ }
+ ++counter;
+ step_timeout(checkCanInsertDTMF, 10);
+ }
+ }, 0);
+ });
+ }).then(() => {
+ return dtmfSender;
+ });
+}
+
+/*
+ Create an RTCDTMFSender and test tonechange events on it.
+ testFunc
+ Test function that is going to manipulate the DTMFSender.
+ It will be called with:
+ t - the test object
+ sender - the created RTCDTMFSender
+ pc - the associated RTCPeerConnection as second argument.
+ toneChanges
+ Array of expected tonechange events fired. The elements
+ are array of 3 items:
+ expectedTone
+ The expected character in event.tone
+ expectedToneBuffer
+ The expected new value of dtmfSender.toneBuffer
+ expectedDuration
+ The rough time since beginning or last tonechange event
+ was fired.
+ desc
+ Test description.
+ */
+function test_tone_change_events(testFunc, toneChanges, desc) {
+ // Convert to cumulative time
+ let cumulativeTime = 0;
+ const cumulativeToneChanges = toneChanges.map(c => {
+ cumulativeTime += c[2];
+ return [c[0], c[1], cumulativeTime];
+ });
+
+ // Wait for same duration as last expected duration + 100ms
+ // before passing test in case there are new tone events fired,
+ // in which case the test should fail.
+ const lastWait = toneChanges.pop()[2] + 100;
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ const dtmfSender = await createDtmfSender(pc);
+ const start = Date.now();
+
+ const allEventsReceived = new Promise(resolve => {
+ const onToneChange = t.step_func(ev => {
+ assert_true(ev instanceof RTCDTMFToneChangeEvent,
+ 'Expect tone change event object to be an RTCDTMFToneChangeEvent');
+
+ const { tone } = ev;
+ assert_equals(typeof tone, 'string',
+ 'Expect event.tone to be the tone string');
+
+ assert_greater_than(cumulativeToneChanges.length, 0,
+ 'More tonechange event is fired than expected');
+
+ const [
+ expectedTone, expectedToneBuffer, expectedTime
+ ] = cumulativeToneChanges.shift();
+
+ assert_equals(tone, expectedTone,
+ `Expect current event.tone to be ${expectedTone}`);
+
+ assert_equals(dtmfSender.toneBuffer, expectedToneBuffer,
+ `Expect dtmfSender.toneBuffer to be updated to ${expectedToneBuffer}`);
+
+ // We check that the cumulative delay is at least the expected one, but
+ // system load may cause random delays, so we do not put any
+ // realistic upper bound on the timing of the events.
+ assert_between_inclusive(Date.now() - start, expectedTime,
+ expectedTime + 4000,
+ `Expect tonechange event for "${tone}" to be fired approximately after ${expectedTime} milliseconds`);
+ if (cumulativeToneChanges.length === 0) {
+ resolve();
+ }
+ });
+
+ dtmfSender.addEventListener('tonechange', onToneChange);
+ });
+
+ testFunc(t, dtmfSender, pc);
+ await allEventsReceived;
+ const wait = ms => new Promise(resolve => t.step_timeout(resolve, ms));
+ await wait(lastWait);
+ }, desc);
+}
+
+// Get the one and only tranceiver from pc.getTransceivers().
+// Assumes that there is only one tranceiver in pc.
+function getTransceiver(pc) {
+ const transceivers = pc.getTransceivers();
+ assert_equals(transceivers.length, 1,
+ 'Expect there to be only one tranceiver in pc');
+
+ return transceivers[0];
+}
--- /dev/null
+'use strict';
+
+const validBinaryTypes = ['blob', 'arraybuffer'];
+const invalidBinaryTypes = ['jellyfish', 'arraybuffer ', '', null, undefined];
+
+for (const binaryType of validBinaryTypes) {
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const dc = pc.createDataChannel('test-binary-type');
+
+ dc.binaryType = binaryType;
+ assert_equals(dc.binaryType, binaryType, `dc.binaryType should be '${binaryType}'`);
+ }, `Setting binaryType to '${binaryType}' should succeed`);
+}
+
+for (const binaryType of invalidBinaryTypes) {
+ test((t) => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const dc = pc.createDataChannel('test-binary-type');
+
+ assert_throws_dom('SyntaxError', () => {
+ dc.binaryType = binaryType;
+ });
+ }, `Setting invalid binaryType '${binaryType}' should throw SyntaxError`);
+}
--- /dev/null
+'use strict'
+
+/*
+ * Helper Methods for testing the following methods in RTCPeerConnection:
+ * createOffer
+ * createAnswer
+ * setLocalDescription
+ * setRemoteDescription
+ *
+ * This file offers the following features:
+ * SDP similarity comparison
+ * Generating offer/answer using anonymous peer connection
+ * Test signalingstatechange event
+ * Test promise that never resolve
+ */
+
+const audioLineRegex = /\r\nm=audio.+\r\n/g;
+const videoLineRegex = /\r\nm=video.+\r\n/g;
+const applicationLineRegex = /\r\nm=application.+\r\n/g;
+
+function countLine(sdp, regex) {
+ const matches = sdp.match(regex);
+ if(matches === null) {
+ return 0;
+ } else {
+ return matches.length;
+ }
+}
+
+function countAudioLine(sdp) {
+ return countLine(sdp, audioLineRegex);
+}
+
+function countVideoLine(sdp) {
+ return countLine(sdp, videoLineRegex);
+}
+
+function countApplicationLine(sdp) {
+ return countLine(sdp, applicationLineRegex);
+}
+
+function similarMediaDescriptions(sdp1, sdp2) {
+ if(sdp1 === sdp2) {
+ return true;
+ } else if(
+ countAudioLine(sdp1) !== countAudioLine(sdp2) ||
+ countVideoLine(sdp1) !== countVideoLine(sdp2) ||
+ countApplicationLine(sdp1) !== countApplicationLine(sdp2))
+ {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+// Assert that given object is either an
+// RTCSessionDescription or RTCSessionDescriptionInit
+function assert_is_session_description(sessionDesc) {
+ if(sessionDesc instanceof RTCSessionDescription) {
+ return;
+ }
+
+ assert_not_equals(sessionDesc, undefined,
+ 'Expect session description to be defined');
+
+ assert_true(typeof(sessionDesc) === 'object',
+ 'Expect sessionDescription to be either a RTCSessionDescription or an object');
+
+ assert_true(typeof(sessionDesc.type) === 'string',
+ 'Expect sessionDescription.type to be a string');
+
+ assert_true(typeof(sessionDesc.sdp) === 'string',
+ 'Expect sessionDescription.sdp to be a string');
+}
+
+
+// We can't do string comparison to the SDP content,
+// because RTCPeerConnection may return SDP that is
+// slightly modified or reordered from what is given
+// to it due to ICE candidate events or serialization.
+// Instead, we create SDP with different number of media
+// lines, and if the SDP strings are not the same, we
+// simply count the media description lines and if they
+// are the same, we assume it is the same.
+function isSimilarSessionDescription(sessionDesc1, sessionDesc2) {
+ assert_is_session_description(sessionDesc1);
+ assert_is_session_description(sessionDesc2);
+
+ if(sessionDesc1.type !== sessionDesc2.type) {
+ return false;
+ } else {
+ return similarMediaDescriptions(sessionDesc1.sdp, sessionDesc2.sdp);
+ }
+}
+
+function assert_session_desc_similar(sessionDesc1, sessionDesc2) {
+ assert_true(isSimilarSessionDescription(sessionDesc1, sessionDesc2),
+ 'Expect both session descriptions to have the same count of media lines');
+}
+
+function assert_session_desc_not_similar(sessionDesc1, sessionDesc2) {
+ assert_false(isSimilarSessionDescription(sessionDesc1, sessionDesc2),
+ 'Expect both session descriptions to have different count of media lines');
+}
+
+async function generateDataChannelOffer(pc) {
+ pc.createDataChannel('test');
+ const offer = await pc.createOffer();
+ assert_equals(countApplicationLine(offer.sdp), 1, 'Expect m=application line to be present in generated SDP');
+ return offer;
+}
+
+async function generateAudioReceiveOnlyOffer(pc)
+{
+ try {
+ pc.addTransceiver('audio', { direction: 'recvonly' });
+ return pc.createOffer();
+ } catch(e) {
+ return pc.createOffer({ offerToReceiveAudio: true });
+ }
+}
+
+async function generateVideoReceiveOnlyOffer(pc)
+{
+ try {
+ pc.addTransceiver('video', { direction: 'recvonly' });
+ return pc.createOffer();
+ } catch(e) {
+ return pc.createOffer({ offerToReceiveVideo: true });
+ }
+}
+
+// Helper function to generate answer based on given offer using a freshly
+// created RTCPeerConnection object
+async function generateAnswer(offer) {
+ const pc = new RTCPeerConnection();
+ await pc.setRemoteDescription(offer);
+ const answer = await pc.createAnswer();
+ pc.close();
+ return answer;
+}
+
+// Helper function to generate offer using a freshly
+// created RTCPeerConnection object
+async function generateOffer() {
+ const pc = new RTCPeerConnection();
+ const offer = await pc.createOffer();
+ pc.close();
+ return offer;
+}
+
+// Run a test function that return a promise that should
+// never be resolved. For lack of better options,
+// we wait for a time out and pass the test if the
+// promise doesn't resolve within that time.
+function test_never_resolve(testFunc, testName) {
+ async_test(t => {
+ testFunc(t)
+ .then(
+ t.step_func(result => {
+ assert_unreached(`Pending promise should never be resolved. Instead it is fulfilled with: ${result}`);
+ }),
+ t.step_func(err => {
+ assert_unreached(`Pending promise should never be resolved. Instead it is rejected with: ${err}`);
+ }));
+
+ t.step_timeout(t.step_func_done(), 100)
+ }, testName);
+}
+
+// Helper function to exchange ice candidates between
+// two local peer connections
+function exchangeIceCandidates(pc1, pc2) {
+ // private function
+ function doExchange(localPc, remotePc) {
+ localPc.addEventListener('icecandidate', event => {
+ const { candidate } = event;
+
+ // Guard against already closed peerconnection to
+ // avoid unrelated exceptions.
+ if (remotePc.signalingState !== 'closed') {
+ remotePc.addIceCandidate(candidate);
+ }
+ });
+ }
+
+ doExchange(pc1, pc2);
+ doExchange(pc2, pc1);
+}
+
+// Returns a promise that resolves when a |name| event is fired.
+function waitUntilEvent(obj, name) {
+ return new Promise(r => obj.addEventListener(name, r, {once: true}));
+}
+
+// Returns a promise that resolves when the |transport.state| is |state|
+// This should work for RTCSctpTransport, RTCDtlsTransport and RTCIceTransport.
+async function waitForState(transport, state) {
+ while (transport.state != state) {
+ await waitUntilEvent(transport, 'statechange');
+ }
+}
+
+// Returns a promise that resolves when |pc.iceConnectionState| is 'connected'
+// or 'completed'.
+async function listenToIceConnected(pc) {
+ await waitForIceStateChange(pc, ['connected', 'completed']);
+}
+
+// Returns a promise that resolves when |pc.iceConnectionState| is in one of the
+// wanted states.
+async function waitForIceStateChange(pc, wantedStates) {
+ while (!wantedStates.includes(pc.iceConnectionState)) {
+ await waitUntilEvent(pc, 'iceconnectionstatechange');
+ }
+}
+
+// Returns a promise that resolves when |pc.connectionState| is 'connected'.
+async function listenToConnected(pc) {
+ while (pc.connectionState != 'connected') {
+ await waitUntilEvent(pc, 'connectionstatechange');
+ }
+}
+
+// Returns a promise that resolves when |pc.connectionState| is in one of the
+// wanted states.
+async function waitForConnectionStateChange(pc, wantedStates) {
+ while (!wantedStates.includes(pc.connectionState)) {
+ await waitUntilEvent(pc, 'connectionstatechange');
+ }
+}
+
+async function waitForIceGatheringState(pc, wantedStates) {
+ while (!wantedStates.includes(pc.iceGatheringState)) {
+ await waitUntilEvent(pc, 'icegatheringstatechange');
+ }
+}
+
+// Resolves when RTP packets have been received.
+async function listenForSSRCs(t, receiver) {
+ while (true) {
+ const ssrcs = receiver.getSynchronizationSources();
+ if (Array.isArray(ssrcs) && ssrcs.length > 0) {
+ return ssrcs;
+ }
+ await new Promise(r => t.step_timeout(r, 0));
+ }
+}
+
+// Helper function to create a pair of connected data channels.
+// On success the promise resolves to an array with two data channels.
+// It does the heavy lifting of performing signaling handshake,
+// ICE candidate exchange, and waiting for data channel at two
+// end points to open. Can do both negotiated and non-negotiated setup.
+async function createDataChannelPair(t, options,
+ pc1 = createPeerConnectionWithCleanup(t),
+ pc2 = createPeerConnectionWithCleanup(t)) {
+ let pair = [], bothOpen;
+ try {
+ if (options.negotiated) {
+ pair = [pc1, pc2].map(pc => pc.createDataChannel('', options));
+ bothOpen = Promise.all(pair.map(dc => new Promise((r, e) => {
+ dc.onopen = r;
+ dc.onerror = ({error}) => e(error);
+ })));
+ } else {
+ pair = [pc1.createDataChannel('', options)];
+ bothOpen = Promise.all([
+ new Promise((r, e) => {
+ pair[0].onopen = r;
+ pair[0].onerror = ({error}) => e(error);
+ }),
+ new Promise((r, e) => pc2.ondatachannel = ({channel}) => {
+ pair[1] = channel;
+ channel.onopen = r;
+ channel.onerror = ({error}) => e(error);
+ })
+ ]);
+ }
+ exchangeIceCandidates(pc1, pc2);
+ await exchangeOfferAnswer(pc1, pc2);
+ await bothOpen;
+ return pair;
+ } finally {
+ for (const dc of pair) {
+ dc.onopen = dc.onerror = null;
+ }
+ }
+}
+
+// Wait for RTP and RTCP stats to arrive
+async function waitForRtpAndRtcpStats(pc) {
+ // If remote stats are never reported, return after 5 seconds.
+ const startTime = performance.now();
+ while (true) {
+ const report = await pc.getStats();
+ const stats = [...report.values()].filter(({type}) => type.endsWith("bound-rtp"));
+ // Each RTP and RTCP stat has a reference
+ // to the matching stat in the other direction
+ if (stats.length && stats.every(({localId, remoteId}) => localId || remoteId)) {
+ break;
+ }
+ if (performance.now() > startTime + 5000) {
+ break;
+ }
+ }
+}
+
+// Wait for a single message event and return
+// a promise that resolve when the event fires
+function awaitMessage(channel) {
+ const once = true;
+ return new Promise((resolve, reject) => {
+ channel.addEventListener('message', ({data}) => resolve(data), {once});
+ channel.addEventListener('error', reject, {once});
+ });
+}
+
+// Helper to convert a blob to array buffer so that
+// we can read the content
+async function blobToArrayBuffer(blob) {
+ const reader = new FileReader();
+ reader.readAsArrayBuffer(blob);
+ return new Promise((resolve, reject) => {
+ reader.addEventListener('load', () => resolve(reader.result), {once: true});
+ reader.addEventListener('error', () => reject(reader.error), {once: true});
+ });
+}
+
+// Assert that two TypedArray or ArrayBuffer objects have the same byte values
+function assert_equals_typed_array(array1, array2) {
+ const [view1, view2] = [array1, array2].map((array) => {
+ if (array instanceof ArrayBuffer) {
+ return new DataView(array);
+ } else {
+ assert_true(array.buffer instanceof ArrayBuffer,
+ 'Expect buffer to be instance of ArrayBuffer');
+ return new DataView(array.buffer, array.byteOffset, array.byteLength);
+ }
+ });
+
+ assert_equals(view1.byteLength, view2.byteLength,
+ 'Expect both arrays to be of the same byte length');
+
+ const byteLength = view1.byteLength;
+
+ for (let i = 0; i < byteLength; ++i) {
+ assert_equals(view1.getUint8(i), view2.getUint8(i),
+ `Expect byte at buffer position ${i} to be equal`);
+ }
+}
+
+// These media tracks will be continually updated with deterministic "noise" in
+// order to ensure UAs do not cease transmission in response to apparent
+// silence.
+//
+// > Many codecs and systems are capable of detecting "silence" and changing
+// > their behavior in this case by doing things such as not transmitting any
+// > media.
+//
+// Source: https://w3c.github.io/webrtc-pc/#offer-answer-options
+const trackFactories = {
+ // Share a single context between tests to avoid exceeding resource limits
+ // without requiring explicit destruction.
+ audioContext: null,
+
+ /**
+ * Given a set of requested media types, determine if the user agent is
+ * capable of procedurally generating a suitable media stream.
+ *
+ * @param {object} requested
+ * @param {boolean} [requested.audio] - flag indicating whether the desired
+ * stream should include an audio track
+ * @param {boolean} [requested.video] - flag indicating whether the desired
+ * stream should include a video track
+ *
+ * @returns {boolean}
+ */
+ canCreate(requested) {
+ const supported = {
+ audio: !!window.AudioContext && !!window.MediaStreamAudioDestinationNode,
+ video: !!HTMLCanvasElement.prototype.captureStream
+ };
+
+ return (!requested.audio || supported.audio) &&
+ (!requested.video || supported.video);
+ },
+
+ audio() {
+ const ctx = trackFactories.audioContext = trackFactories.audioContext ||
+ new AudioContext();
+ const oscillator = ctx.createOscillator();
+ const dst = oscillator.connect(ctx.createMediaStreamDestination());
+ oscillator.start();
+ return dst.stream.getAudioTracks()[0];
+ },
+
+ video({width = 640, height = 480, signal} = {}) {
+ const canvas = Object.assign(
+ document.createElement("canvas"), {width, height}
+ );
+ const ctx = canvas.getContext('2d');
+ const stream = canvas.captureStream();
+
+ let count = 0;
+ const interval = setInterval(() => {
+ ctx.fillStyle = `rgb(${count%255}, ${count*count%255}, ${count%255})`;
+ count += 1;
+ ctx.fillRect(0, 0, width, height);
+ // Add some bouncing boxes in contrast color to add a little more noise.
+ const contrast = count + 128;
+ ctx.fillStyle = `rgb(${contrast%255}, ${contrast*contrast%255}, ${contrast%255})`;
+ const xpos = count % (width - 20);
+ const ypos = count % (height - 20);
+ ctx.fillRect(xpos, ypos, xpos + 20, ypos + 20);
+ const xpos2 = (count + width / 2) % (width - 20);
+ const ypos2 = (count + height / 2) % (height - 20);
+ ctx.fillRect(xpos2, ypos2, xpos2 + 20, ypos2 + 20);
+ // If signal is set (0-255), add a constant-color box of that luminance to
+ // the video frame at coordinates 20 to 60 in both X and Y direction.
+ // (big enough to avoid color bleed from surrounding video in some codecs,
+ // for more stable tests).
+ if (signal != undefined) {
+ ctx.fillStyle = `rgb(${signal}, ${signal}, ${signal})`;
+ ctx.fillRect(20, 20, 40, 40);
+ }
+ }, 100);
+
+ if (document.body) {
+ document.body.appendChild(canvas);
+ } else {
+ document.addEventListener('DOMContentLoaded', () => {
+ document.body.appendChild(canvas);
+ }, {once: true});
+ }
+
+ // Implement track.stop() for performance in some tests on some platforms
+ const track = stream.getVideoTracks()[0];
+ const nativeStop = track.stop;
+ track.stop = function stop() {
+ clearInterval(interval);
+ nativeStop.apply(this);
+ if (document.body && canvas.parentElement == document.body) {
+ document.body.removeChild(canvas);
+ }
+ };
+ return track;
+ }
+};
+
+// Get the signal from a video element inserted by createNoiseStream
+function getVideoSignal(v) {
+ if (v.videoWidth < 60 || v.videoHeight < 60) {
+ throw new Error('getVideoSignal: video too small for test');
+ }
+ const canvas = document.createElement("canvas");
+ canvas.width = canvas.height = 60;
+ const context = canvas.getContext('2d');
+ context.drawImage(v, 0, 0);
+ // Extract pixel value at position 40, 40
+ const pixel = context.getImageData(40, 40, 1, 1);
+ // Use luma reconstruction to get back original value according to
+ // ITU-R rec BT.709
+ return (pixel.data[0] * 0.21 + pixel.data[1] * 0.72 + pixel.data[2] * 0.07);
+}
+
+async function detectSignal(t, v, value) {
+ while (true) {
+ const signal = getVideoSignal(v).toFixed();
+ // allow off-by-two pixel error (observed in some implementations)
+ if (value - 2 <= signal && signal <= value + 2) {
+ return;
+ }
+ // We would like to wait for each new frame instead here,
+ // but there seems to be no such callback.
+ await new Promise(r => t.step_timeout(r, 100));
+ }
+}
+
+// Generate a MediaStream bearing the specified tracks.
+//
+// @param {object} [caps]
+// @param {boolean} [caps.audio] - flag indicating whether the generated stream
+// should include an audio track
+// @param {boolean} [caps.video] - flag indicating whether the generated stream
+// should include a video track, or parameters for video
+async function getNoiseStream(caps = {}) {
+ if (!trackFactories.canCreate(caps)) {
+ return navigator.mediaDevices.getUserMedia(caps);
+ }
+ const tracks = [];
+
+ if (caps.audio) {
+ tracks.push(trackFactories.audio());
+ }
+
+ if (caps.video) {
+ tracks.push(trackFactories.video(caps.video));
+ }
+
+ return new MediaStream(tracks);
+}
+
+// Obtain a MediaStreamTrack of kind using procedurally-generated streams (and
+// falling back to `getUserMedia` when the user agent cannot generate the
+// requested streams).
+// Return Promise of pair of track and associated mediaStream.
+// Assumes that there is at least one available device
+// to generate the track.
+function getTrackFromUserMedia(kind) {
+ return getNoiseStream({ [kind]: true })
+ .then(mediaStream => {
+ const [track] = mediaStream.getTracks();
+ return [track, mediaStream];
+ });
+}
+
+// Obtain |count| MediaStreamTracks of type |kind| and MediaStreams. The tracks
+// do not belong to any stream and the streams are empty. Returns a Promise
+// resolved with a pair of arrays [tracks, streams].
+// Assumes there is at least one available device to generate the tracks and
+// streams and that the getUserMedia() calls resolve.
+function getUserMediaTracksAndStreams(count, type = 'audio') {
+ let otherTracksPromise;
+ if (count > 1)
+ otherTracksPromise = getUserMediaTracksAndStreams(count - 1, type);
+ else
+ otherTracksPromise = Promise.resolve([[], []]);
+ return otherTracksPromise.then(([tracks, streams]) => {
+ return getTrackFromUserMedia(type)
+ .then(([track, stream]) => {
+ // Remove the default stream-track relationship.
+ stream.removeTrack(track);
+ tracks.push(track);
+ streams.push(stream);
+ return [tracks, streams];
+ });
+ });
+}
+
+// Performs an offer exchange caller -> callee.
+async function exchangeOffer(caller, callee) {
+ await caller.setLocalDescription(await caller.createOffer());
+ await callee.setRemoteDescription(caller.localDescription);
+}
+// Performs an answer exchange caller -> callee.
+async function exchangeAnswer(caller, callee) {
+ // Note that caller's remote description must be set first; if not,
+ // there's a chance that candidates from callee arrive at caller before
+ // it has a remote description to apply them to.
+ const answer = await callee.createAnswer();
+ await caller.setRemoteDescription(answer);
+ await callee.setLocalDescription(answer);
+}
+async function exchangeOfferAnswer(caller, callee) {
+ await exchangeOffer(caller, callee);
+ await exchangeAnswer(caller, callee);
+}
+
+// The returned promise is resolved with caller's ontrack event.
+async function exchangeAnswerAndListenToOntrack(t, caller, callee) {
+ const ontrackPromise = addEventListenerPromise(t, caller, 'track');
+ await exchangeAnswer(caller, callee);
+ return ontrackPromise;
+}
+// The returned promise is resolved with callee's ontrack event.
+async function exchangeOfferAndListenToOntrack(t, caller, callee) {
+ const ontrackPromise = addEventListenerPromise(t, callee, 'track');
+ await exchangeOffer(caller, callee);
+ return ontrackPromise;
+}
+
+// The resolver extends a |promise| that can be resolved or rejected using |resolve|
+// or |reject|.
+class Resolver extends Promise {
+ constructor(executor) {
+ let resolve, reject;
+ super((resolve_, reject_) => {
+ resolve = resolve_;
+ reject = reject_;
+ if (executor) {
+ return executor(resolve_, reject_);
+ }
+ });
+
+ this._done = false;
+ this._resolve = resolve;
+ this._reject = reject;
+ }
+
+ /**
+ * Return whether the promise is done (resolved or rejected).
+ */
+ get done() {
+ return this._done;
+ }
+
+ /**
+ * Resolve the promise.
+ */
+ resolve(...args) {
+ this._done = true;
+ return this._resolve(...args);
+ }
+
+ /**
+ * Reject the promise.
+ */
+ reject(...args) {
+ this._done = true;
+ return this._reject(...args);
+ }
+}
+
+function addEventListenerPromise(t, obj, type, listener) {
+ if (!listener) {
+ return waitUntilEvent(obj, type);
+ }
+ return new Promise(r => obj.addEventListener(type,
+ t.step_func(e => r(listener(e))),
+ {once: true}));
+}
+
+function createPeerConnectionWithCleanup(t) {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ return pc;
+}
+
+async function createTrackAndStreamWithCleanup(t, kind = 'audio') {
+ let constraints = {};
+ constraints[kind] = true;
+ const stream = await getNoiseStream(constraints);
+ const [track] = stream.getTracks();
+ t.add_cleanup(() => track.stop());
+ return [track, stream];
+}
+
+function findTransceiverForSender(pc, sender) {
+ const transceivers = pc.getTransceivers();
+ for (let i = 0; i < transceivers.length; ++i) {
+ if (transceivers[i].sender == sender)
+ return transceivers[i];
+ }
+ return null;
+}
+
+function preferCodec(transceiver, mimeType, sdpFmtpLine) {
+ const {codecs} = RTCRtpSender.getCapabilities(transceiver.receiver.track.kind);
+ // sdpFmtpLine is optional, pick the first partial match if not given.
+ const selectedCodecIndex = codecs.findIndex(c => {
+ return c.mimeType === mimeType && (c.sdpFmtpLine === sdpFmtpLine || !sdpFmtpLine);
+ });
+ const selectedCodec = codecs[selectedCodecIndex];
+ codecs.slice(selectedCodecIndex, 1);
+ codecs.unshift(selectedCodec);
+ return transceiver.setCodecPreferences(codecs);
+}
+
+// Contains a set of values and will yell at you if you try to add a value twice.
+class UniqueSet extends Set {
+ constructor(items) {
+ super();
+ if (items !== undefined) {
+ for (const item of items) {
+ this.add(item);
+ }
+ }
+ }
+
+ add(value, message) {
+ if (message === undefined) {
+ message = `Value '${value}' needs to be unique but it is already in the set`;
+ }
+ assert_true(!this.has(value), message);
+ super.add(value);
+ }
+}
+
+const iceGatheringStateTransitions = async (pc, ...states) => {
+ for (const state of states) {
+ await new Promise((resolve, reject) => {
+ pc.addEventListener('icegatheringstatechange', () => {
+ if (pc.iceGatheringState == state) {
+ resolve();
+ } else {
+ reject(`Unexpected gathering state: ${pc.iceGatheringState}, was expecting ${state}`);
+ }
+ }, {once: true});
+ });
+ }
+};
+
+const initialOfferAnswerWithIceGatheringStateTransitions =
+ async (pc1, pc2, offerOptions) => {
+ await pc1.setLocalDescription(
+ await pc1.createOffer(offerOptions));
+ const pc1Transitions =
+ iceGatheringStateTransitions(pc1, 'gathering', 'complete');
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription(await pc2.createAnswer());
+ const pc2Transitions =
+ iceGatheringStateTransitions(pc2, 'gathering', 'complete');
+ await pc1.setRemoteDescription(pc2.localDescription);
+ await pc1Transitions;
+ await pc2Transitions;
+ };
+
+const expectNoMoreGatheringStateChanges = async (t, pc) => {
+ pc.onicegatheringstatechange =
+ t.step_func(() => {
+ assert_unreached(
+ 'Should not get an icegatheringstatechange right now!');
+ });
+};
--- /dev/null
+'use strict'
+
+function peer(other, polite, fail = null) {
+ const send = (tgt, msg) => tgt.postMessage(JSON.parse(JSON.stringify(msg)),
+ "*");
+ if (!fail) fail = e => send(window.parent, {error: `${e.name}: ${e.message}`});
+ const pc = new RTCPeerConnection();
+
+ if (!window.assert_equals) {
+ window.assert_equals = (a, b, msg) => a === b ||
+ fail(new Error(`${msg} expected ${b} but got ${a}`));
+ }
+
+ const commands = {
+ async addTransceiver() {
+ const transceiver = pc.addTransceiver("video");
+ await new Promise(r => pc.addEventListener("negotiated", r, {once: true}));
+ if (!transceiver.currentDirection) {
+ // Might have just missed the negotiation train. Catch next one.
+ await new Promise(r => pc.addEventListener("negotiated", r, {once: true}));
+ }
+ assert_equals(transceiver.currentDirection, "sendonly", "have direction");
+ return pc.getTransceivers().length;
+ },
+ async simpleConnect() {
+ const p = commands.addTransceiver();
+ await new Promise(r => pc.oniceconnectionstatechange =
+ () => pc.iceConnectionState == "connected" && r());
+ return await p;
+ },
+ async getNumTransceivers() {
+ return pc.getTransceivers().length;
+ },
+ };
+
+ try {
+ pc.addEventListener("icecandidate", ({candidate}) => send(other,
+ {candidate}));
+ let makingOffer = false, ignoreIceCandidateFailures = false;
+ let srdAnswerPending = false;
+ pc.addEventListener("negotiationneeded", async () => {
+ try {
+ assert_equals(pc.signalingState, "stable", "negotiationneeded always fires in stable state");
+ assert_equals(makingOffer, false, "negotiationneeded not already in progress");
+ makingOffer = true;
+ await pc.setLocalDescription();
+ assert_equals(pc.signalingState, "have-local-offer", "negotiationneeded not racing with onmessage");
+ assert_equals(pc.localDescription.type, "offer", "negotiationneeded SLD worked");
+ send(other, {description: pc.localDescription});
+ } catch (e) {
+ fail(e);
+ } finally {
+ makingOffer = false;
+ }
+ });
+ window.onmessage = async ({data: {description, candidate, run}}) => {
+ try {
+ if (description) {
+ // If we have a setRemoteDescription() answer operation pending, then
+ // we will be "stable" by the time the next setRemoteDescription() is
+ // executed, so we count this being stable when deciding whether to
+ // ignore the offer.
+ let isStable =
+ pc.signalingState == "stable" ||
+ (pc.signalingState == "have-local-offer" && srdAnswerPending);
+ const ignoreOffer = description.type == "offer" && !polite &&
+ (makingOffer || !isStable);
+ if (ignoreOffer) {
+ ignoreIceCandidateFailures = true;
+ return;
+ }
+ if (description.type == "answer")
+ srdAnswerPending = true;
+ await pc.setRemoteDescription(description);
+ ignoreIceCandidateFailures = false;
+ srdAnswerPending = false;
+ if (description.type == "offer") {
+ assert_equals(pc.signalingState, "have-remote-offer", "Remote offer");
+ assert_equals(pc.remoteDescription.type, "offer", "SRD worked");
+ await pc.setLocalDescription();
+ assert_equals(pc.signalingState, "stable", "onmessage not racing with negotiationneeded");
+ assert_equals(pc.localDescription.type, "answer", "onmessage SLD worked");
+ send(other, {description: pc.localDescription});
+ } else {
+ assert_equals(pc.remoteDescription.type, "answer", "Answer was set");
+ assert_equals(pc.signalingState, "stable", "answered");
+ pc.dispatchEvent(new Event("negotiated"));
+ }
+ } else if (candidate) {
+ try {
+ await pc.addIceCandidate(candidate);
+ } catch (e) {
+ if (!ignoreIceCandidateFailures) throw e;
+ }
+ } else if (run) {
+ send(window.parent, {[run.id]: await commands[run.cmd]() || 0});
+ }
+ } catch (e) {
+ fail(e);
+ }
+ };
+ } catch (e) {
+ fail(e);
+ }
+ return pc;
+}
+
+async function setupPeerIframe(t, polite) {
+ const iframe = document.createElement("iframe");
+ t.add_cleanup(() => iframe.remove());
+ iframe.srcdoc =
+ `<html\><script\>(${peer.toString()})(window.parent, ${polite});</script\></html\>`;
+ document.documentElement.appendChild(iframe);
+
+ const failCatcher = t.step_func(({data}) =>
+ ("error" in data) && assert_unreached(`Error in iframe: ${data.error}`));
+ window.addEventListener("message", failCatcher);
+ t.add_cleanup(() => window.removeEventListener("message", failCatcher));
+ await new Promise(r => iframe.onload = r);
+ return iframe;
+}
+
+function setupPeerTopLevel(t, other, polite) {
+ const pc = peer(other, polite, t.step_func(e => { throw e; }));
+ t.add_cleanup(() => { pc.close(); window.onmessage = null; });
+}
+
+let counter = 0;
+async function run(target, cmd) {
+ const id = `result${counter++}`;
+ target.postMessage({run: {cmd, id}}, "*");
+ return new Promise(r => window.addEventListener("message",
+ function listen({data}) {
+ if (!(id in data)) return;
+ window.removeEventListener("message", listen);
+ r(data[id]);
+ }));
+}
+
+let iframe;
+async function setupAB(t, politeA, politeB) {
+ iframe = await setupPeerIframe(t, politeB);
+ return setupPeerTopLevel(t, iframe.contentWindow, politeA);
+}
+const runA = cmd => run(window, cmd);
+const runB = cmd => run(iframe.contentWindow, cmd);
+const runBoth = (cmdA, cmdB = cmdA) => Promise.all([runA(cmdA), runB(cmdB)]);
+
+async function promise_test_both_roles(f, name) {
+ promise_test(async t => f(t, await setupAB(t, true, false)), name);
+ promise_test(async t => f(t, await setupAB(t, false, true)),
+ `${name} with roles reversed`);
+}
--- /dev/null
+'use strict'
+
+// Test is based on the following editor draft:
+// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+// This file depends on dictionary-helper.js which should
+// be loaded from the main HTML file.
+
+/*
+ 5.2. RTCRtpSender Interface
+ dictionary RTCRtpCapabilities {
+ sequence<RTCRtpCodecCapability> codecs;
+ sequence<RTCRtpHeaderExtensionCapability> headerExtensions;
+ };
+
+ dictionary RTCRtpCodecCapability {
+ DOMString mimeType;
+ unsigned long clockRate;
+ unsigned short channels;
+ DOMString sdpFmtpLine;
+ };
+
+ dictionary RTCRtpHeaderExtensionCapability {
+ DOMString uri;
+ };
+ */
+
+function validateRtpCapabilities(capabilities) {
+ assert_array_field(capabilities, 'codecs');
+ for(const codec of capabilities.codecs) {
+ validateCodecCapability(codec);
+ }
+
+ assert_greater_than(capabilities.codecs.length, 0,
+ 'Expect at least one codec capability available');
+
+ assert_array_field(capabilities, 'headerExtensions');
+ for(const headerExt of capabilities.headerExtensions) {
+ validateHeaderExtensionCapability(headerExt);
+ }
+}
+
+function validateCodecCapability(codec) {
+ assert_optional_string_field(codec, 'mimeType');
+ assert_optional_unsigned_int_field(codec, 'clockRate');
+ assert_optional_unsigned_int_field(codec, 'channels');
+ assert_optional_string_field(codec, 'sdpFmtpLine');
+}
+
+function validateHeaderExtensionCapability(headerExt) {
+ assert_optional_string_field(headerExt, 'uri');
+}
--- /dev/null
+'use strict';
+
+// Test is based on the following editor draft:
+// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
+
+// Helper function for testing RTCRtpParameters dictionary fields
+
+// This file depends on dictionary-helper.js which should
+// be loaded from the main HTML file.
+
+// An offer/answer exchange is necessary for getParameters() to have any
+// negotiated parameters to return.
+async function doOfferAnswerExchange(t, caller) {
+ const callee = new RTCPeerConnection();
+ t.add_cleanup(() => callee.close());
+ const offer = await caller.createOffer();
+ await caller.setLocalDescription(offer);
+ await callee.setRemoteDescription(offer);
+ const answer = await callee.createAnswer();
+ await callee.setLocalDescription(answer);
+ await caller.setRemoteDescription(answer);
+
+ return callee;
+}
+
+/*
+ Validates the RTCRtpParameters returned from RTCRtpSender.prototype.getParameters
+
+ 5.2. RTCRtpSender Interface
+ getParameters
+ - transactionId is set to a new unique identifier, used to match this getParameters
+ call to a setParameters call that may occur later.
+
+ - encodings is set to the value of the [[SendEncodings]] internal slot.
+
+ - The headerExtensions sequence is populated based on the header extensions that
+ have been negotiated for sending.
+
+ - The codecs sequence is populated based on the codecs that have been negotiated
+ for sending, and which the user agent is currently capable of sending. If
+ setParameters has removed or reordered codecs, getParameters MUST return the
+ shortened/reordered list. However, every time codecs are renegotiated by a
+ new offer/answer exchange, the list of codecs MUST be restored to the full
+ negotiated set, in the priority order indicated by the remote description,
+ in effect discarding the effects of setParameters.
+
+ - rtcp.cname is set to the CNAME of the associated RTCPeerConnection. rtcp.reducedSize
+ is set to true if reduced-size RTCP has been negotiated for sending, and false otherwise.
+ */
+function validateSenderRtpParameters(param) {
+ validateRtpParameters(param);
+
+ assert_array_field(param, 'encodings');
+ for(const encoding of param.encodings) {
+ validateEncodingParameters(encoding);
+ }
+
+ assert_not_equals(param.transactionId, undefined,
+ 'Expect sender param.transactionId to be set');
+
+ assert_not_equals(param.rtcp.cname, undefined,
+ 'Expect sender param.rtcp.cname to be set');
+
+ assert_not_equals(param.rtcp.reducedSize, undefined,
+ 'Expect sender param.rtcp.reducedSize to be set to either true or false');
+}
+
+/*
+ Validates the RTCRtpParameters returned from RTCRtpReceiver.prototype.getParameters
+
+ 5.3. RTCRtpReceiver Interface
+ getParameters
+ When getParameters is called, the RTCRtpParameters dictionary is constructed
+ as follows:
+
+ - The headerExtensions sequence is populated based on the header extensions that
+ the receiver is currently prepared to receive.
+
+ - The codecs sequence is populated based on the codecs that the receiver is currently
+ prepared to receive.
+
+ - rtcp.reducedSize is set to true if the receiver is currently prepared to receive
+ reduced-size RTCP packets, and false otherwise. rtcp.cname is left undefined.
+
+ - transactionId is left undefined.
+ */
+function validateReceiverRtpParameters(param) {
+ validateRtpParameters(param);
+
+ assert_equals(param.transactionId, undefined,
+ 'Expect receiver param.transactionId to be unset');
+
+ assert_not_equals(param.rtcp.reducedSize, undefined,
+ 'Expect receiver param.rtcp.reducedSize to be set');
+
+ assert_equals(param.rtcp.cname, undefined,
+ 'Expect receiver param.rtcp.cname to be unset');
+}
+
+/*
+ dictionary RTCRtpParameters {
+ DOMString transactionId;
+ sequence<RTCRtpEncodingParameters> encodings;
+ sequence<RTCRtpHeaderExtensionParameters> headerExtensions;
+ RTCRtcpParameters rtcp;
+ sequence<RTCRtpCodecParameters> codecs;
+ };
+
+ */
+function validateRtpParameters(param) {
+ assert_optional_string_field(param, 'transactionId');
+
+ assert_array_field(param, 'headerExtensions');
+ for(const headerExt of param.headerExtensions) {
+ validateHeaderExtensionParameters(headerExt);
+ }
+
+ assert_dict_field(param, 'rtcp');
+ validateRtcpParameters(param.rtcp);
+
+ assert_array_field(param, 'codecs');
+ for(const codec of param.codecs) {
+ validateCodecParameters(codec);
+ }
+}
+
+/*
+ dictionary RTCRtpEncodingParameters {
+ boolean active;
+ unsigned long maxBitrate;
+
+ [readonly]
+ DOMString rid;
+
+ double scaleResolutionDownBy;
+ };
+
+ */
+function validateEncodingParameters(encoding) {
+ assert_optional_boolean_field(encoding, 'active');
+ assert_optional_unsigned_int_field(encoding, 'maxBitrate');
+
+ assert_optional_string_field(encoding, 'rid');
+ assert_optional_number_field(encoding, 'scaleResolutionDownBy');
+}
+
+/*
+ dictionary RTCRtcpParameters {
+ [readonly]
+ DOMString cname;
+
+ [readonly]
+ boolean reducedSize;
+ };
+ */
+function validateRtcpParameters(rtcp) {
+ assert_optional_string_field(rtcp, 'cname');
+ assert_optional_boolean_field(rtcp, 'reducedSize');
+}
+
+/*
+ dictionary RTCRtpHeaderExtensionParameters {
+ [readonly]
+ DOMString uri;
+
+ [readonly]
+ unsigned short id;
+
+ [readonly]
+ boolean encrypted;
+ };
+ */
+function validateHeaderExtensionParameters(headerExt) {
+ assert_optional_string_field(headerExt, 'uri');
+ assert_optional_unsigned_int_field(headerExt, 'id');
+ assert_optional_boolean_field(headerExt, 'encrypted');
+}
+
+/*
+ dictionary RTCRtpCodecParameters {
+ [readonly]
+ unsigned short payloadType;
+
+ [readonly]
+ DOMString mimeType;
+
+ [readonly]
+ unsigned long clockRate;
+
+ [readonly]
+ unsigned short channels;
+
+ [readonly]
+ DOMString sdpFmtpLine;
+ };
+ */
+function validateCodecParameters(codec) {
+ assert_optional_unsigned_int_field(codec, 'payloadType');
+ assert_optional_string_field(codec, 'mimeType');
+ assert_optional_unsigned_int_field(codec, 'clockRate');
+ assert_optional_unsigned_int_field(codec, 'channels');
+ assert_optional_string_field(codec, 'sdpFmtpLine');
+}
+
+// Get the first encoding in param.encodings.
+// Asserts that param.encodings has at least one element.
+function getFirstEncoding(param) {
+ const {
+ encodings
+ } = param;
+ assert_equals(encodings.length, 1);
+ return encodings[0];
+}
+
+// Helper function to test that modifying an encoding field should succeed
+function test_modified_encoding(kind, field, value1, value2, desc) {
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {
+ sender
+ } = pc.addTransceiver(kind, {
+ sendEncodings: [{
+ [field]: value1
+ }]
+ });
+ await doOfferAnswerExchange(t, pc);
+
+ const param1 = sender.getParameters();
+ validateSenderRtpParameters(param1);
+ const encoding1 = getFirstEncoding(param1);
+
+ assert_equals(encoding1[field], value1);
+ encoding1[field] = value2;
+
+ await sender.setParameters(param1);
+ const param2 = sender.getParameters();
+ validateSenderRtpParameters(param2);
+ const encoding2 = getFirstEncoding(param2);
+ assert_equals(encoding2[field], value2);
+ }, desc + ' with RTCRtpTransceiverInit');
+
+ promise_test(async t => {
+ const pc = new RTCPeerConnection();
+ t.add_cleanup(() => pc.close());
+ const {
+ sender
+ } = pc.addTransceiver(kind);
+ await doOfferAnswerExchange(t, pc);
+
+ const initParam = sender.getParameters();
+ validateSenderRtpParameters(initParam);
+ initParam.encodings[0][field] = value1;
+ await sender.setParameters(initParam);
+
+ const param1 = sender.getParameters();
+ validateSenderRtpParameters(param1);
+ const encoding1 = getFirstEncoding(param1);
+
+ assert_equals(encoding1[field], value1);
+ encoding1[field] = value2;
+
+ await sender.setParameters(param1);
+ const param2 = sender.getParameters();
+ validateSenderRtpParameters(param2);
+ const encoding2 = getFirstEncoding(param2);
+ assert_equals(encoding2[field], value2);
+ }, desc + ' without RTCRtpTransceiverInit');
+}
--- /dev/null
+'use strict';
+
+// Test is based on the following editor draft:
+// webrtc-pc 20171130
+// webrtc-stats 20171122
+
+// This file depends on dictionary-helper.js which should
+// be loaded from the main HTML file.
+
+/*
+ [webrtc-stats]
+ 6.1. RTCStatsType enum
+ enum RTCStatsType {
+ "codec",
+ "inbound-rtp",
+ "outbound-rtp",
+ "remote-inbound-rtp",
+ "remote-outbound-rtp",
+ "csrc",
+ "peer-connection",
+ "data-channel",
+ "stream",
+ "track",
+ "transport",
+ "candidate-pair",
+ "local-candidate",
+ "remote-candidate",
+ "certificate",
+ "ice-server"
+ };
+ */
+const statsValidatorTable = {
+ 'codec': validateCodecStats,
+ 'inbound-rtp': validateInboundRtpStreamStats,
+ 'outbound-rtp': validateOutboundRtpStreamStats,
+ 'remote-inbound-rtp': validateRemoteInboundRtpStreamStats,
+ 'remote-outbound-rtp': validateRemoteOutboundRtpStreamStats,
+ 'media-source': validateMediaSourceStats,
+ 'csrc': validateContributingSourceStats,
+ 'peer-connection': validatePeerConnectionStats,
+ 'data-channel': validateDataChannelStats,
+ 'transceiver': validateTransceiverStats,
+ 'sender': validateSenderStats,
+ 'receiver': validateReceiverStats,
+ 'transport': validateTransportStats,
+ 'candidate-pair': validateIceCandidatePairStats,
+ 'local-candidate': validateIceCandidateStats,
+ 'remote-candidate': validateIceCandidateStats,
+ 'certificate': validateCertificateStats,
+ 'ice-server': validateIceServerStats
+};
+
+// Validate that the stats objects in a stats report
+// follows the respective definitions.
+// Stats objects with unknown type are ignored and
+// only basic validation is done.
+function validateStatsReport(statsReport) {
+ for(const [id, stats] of statsReport.entries()) {
+ assert_equals(stats.id, id,
+ 'expect stats.id to be the same as the key in statsReport');
+
+ const validator = statsValidatorTable[stats.type];
+ if(validator) {
+ validator(statsReport, stats);
+ } else {
+ validateRtcStats(statsReport, stats);
+ }
+ }
+}
+
+// Assert that the stats report have stats objects of
+// given types
+function assert_stats_report_has_stats(statsReport, statsTypes) {
+ const hasTypes = new Set([...statsReport.values()]
+ .map(stats => stats.type));
+
+ for(const type of statsTypes) {
+ assert_true(hasTypes.has(type),
+ `Expect statsReport to contain stats object of type ${type}`);
+ }
+}
+
+function findStatsFromReport(statsReport, predicate, message) {
+ for (const stats of statsReport.values()) {
+ if (predicate(stats)) {
+ return stats;
+ }
+ }
+
+ assert_unreached(message || 'none of stats in statsReport satisfy given condition')
+}
+
+// Get stats object of type that is expected to be
+// found in the statsReport
+function getRequiredStats(statsReport, type) {
+ for(const stats of statsReport.values()) {
+ if(stats.type === type) {
+ return stats;
+ }
+ }
+
+ assert_unreached(`required stats of type ${type} is not found in stats report`);
+}
+
+// Get stats object by the stats ID.
+// This is used to retreive other stats objects
+// linked to a stats object
+function getStatsById(statsReport, statsId) {
+ assert_true(statsReport.has(statsId),
+ `Expect stats report to have stats object with id ${statsId}`);
+
+ return statsReport.get(statsId);
+}
+
+// Validate an ID field in a stats object by making sure
+// that the linked stats object is found in the stats report
+// and have the type field value same as expected type
+// It doesn't validate the other fields of the linked stats
+// as validateStatsReport already does all validations
+function validateIdField(statsReport, stats, field, type) {
+ assert_string_field(stats, field);
+ const linkedStats = getStatsById(statsReport, stats[field]);
+ assert_equals(linkedStats.type, type,
+ `Expect linked stats object to have type ${type}`);
+}
+
+function validateOptionalIdField(statsReport, stats, field, type) {
+ if(stats[field] !== undefined) {
+ validateIdField(statsReport, stats, field, type);
+ }
+}
+
+/*
+ [webrtc-pc]
+ 8.4. RTCStats Dictionary
+ dictionary RTCStats {
+ required DOMHighResTimeStamp timestamp;
+ required RTCStatsType type;
+ required DOMString id;
+ };
+ */
+function validateRtcStats(statsReport, stats) {
+ assert_number_field(stats, 'timestamp');
+ assert_string_field(stats, 'type');
+ assert_string_field(stats, 'id');
+}
+
+/*
+ [webrtc-stats]
+ 7.1. RTCRtpStreamStats dictionary
+ dictionary RTCRtpStreamStats : RTCStats {
+ unsigned long ssrc;
+ DOMString kind;
+ DOMString transportId;
+ DOMString codecId;
+ };
+
+ kind of type DOMString
+ Either "audio" or "video".
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRtpStreamStats, with attributes ssrc, kind, transportId, codecId
+ */
+function validateRtpStreamStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'ssrc');
+ assert_string_field(stats, 'kind');
+ assert_enum_field(stats, 'kind', ['audio', 'video'])
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ validateIdField(statsReport, stats, 'codecId', 'codec');
+
+}
+
+/*
+ [webrtc-stats]
+ 7.2. RTCCodecStats dictionary
+ dictionary RTCCodecStats : RTCStats {
+ required unsigned long payloadType;
+ RTCCodecType codecType;
+ required DOMString transportId;
+ required DOMString mimeType;
+ unsigned long clockRate;
+ unsigned long channels;
+ DOMString sdpFmtpLine;
+ };
+
+ enum RTCCodecType {
+ "encode",
+ "decode",
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCCodecStats, with attributes payloadType, codecType, mimeType, clockRate, channels, sdpFmtpLine
+ */
+
+function validateCodecStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'payloadType');
+ assert_optional_enum_field(stats, 'codecType', ['encode', 'decode']);
+
+ validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
+
+ assert_string_field(stats, 'mimeType');
+ assert_unsigned_int_field(stats, 'clockRate');
+ if (stats.kind === 'audio') {
+ assert_unsigned_int_field(stats, 'channels');
+ }
+ assert_string_field(stats, 'sdpFmtpLine');
+}
+
+/*
+ [webrtc-stats]
+ 7.3. RTCReceivedRtpStreamStats dictionary
+ dictionary RTCReceivedRtpStreamStats : RTCRtpStreamStats {
+ unsigned long long packetsReceived;
+ long long packetsLost;
+ double jitter;
+ unsigned long long packetsDiscarded;
+ unsigned long long packetsRepaired;
+ unsigned long long burstPacketsLost;
+ unsigned long long burstPacketsDiscarded;
+ unsigned long burstLossCount;
+ unsigned long burstDiscardCount;
+ double burstLossRate;
+ double burstDiscardRate;
+ double gapLossRate;
+ double gapDiscardRate;
+ unsigned long framesDropped;
+ unsigned long partialFramesLost;
+ unsigned long fullFramesLost;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCReceivedRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes packetsReceived,
+ packetsLost, jitter, packetsDiscarded, framesDropped
+ */
+function validateReceivedRtpStreamStats(statsReport, stats) {
+ validateRtpStreamStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'packetsLost');
+
+ assert_number_field(stats, 'jitter');
+
+ assert_unsigned_int_field(stats, 'packetsDiscarded');
+ assert_unsigned_int_field(stats, 'framesDropped');
+
+ assert_optional_unsigned_int_field(stats, 'packetsRepaired');
+ assert_optional_unsigned_int_field(stats, 'burstPacketsLost');
+ assert_optional_unsigned_int_field(stats, 'burstPacketsDiscarded');
+ assert_optional_unsigned_int_field(stats, 'burstLossCount');
+ assert_optional_unsigned_int_field(stats, 'burstDiscardCount');
+
+ assert_optional_number_field(stats, 'burstLossRate');
+ assert_optional_number_field(stats, 'burstDiscardRate');
+ assert_optional_number_field(stats, 'gapLossRate');
+ assert_optional_number_field(stats, 'gapDiscardRate');
+
+ assert_optional_unsigned_int_field(stats, 'partialFramesLost');
+ assert_optional_unsigned_int_field(stats, 'fullFramesLost');
+}
+
+/*
+ [webrtc-stats]
+ 7.4. RTCInboundRtpStreamStats dictionary
+ dictionary RTCInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+ DOMString trackId;
+ DOMString receiverId;
+ DOMString remoteId;
+ unsigned long framesDecoded;
+ unsigned long keyFramesDecoded;
+ unsigned long frameWidth;
+ unsigned long frameHeight;
+ unsigned long frameBitDepth;
+ double framesPerSecond;
+ unsigned long long qpSum;
+ double totalDecodeTime;
+ double totalInterFrameDelay;
+ double totalSquaredInterFrameDelay;
+ boolean voiceActivityFlag;
+ DOMHighResTimeStamp lastPacketReceivedTimestamp;
+ double averageRtcpInterval;
+ unsigned long long headerBytesReceived;
+ unsigned long long fecPacketsReceived;
+ unsigned long long fecPacketsDiscarded;
+ unsigned long long bytesReceived;
+ unsigned long long packetsFailedDecryption;
+ unsigned long long packetsDuplicated;
+ record<USVString, unsigned long long> perDscpPacketsReceived;
+ unsigned long nackCount;
+ unsigned long firCount;
+ unsigned long pliCount;
+ unsigned long sliCount;
+ DOMHighResTimeStamp estimatedPlayoutTimestamp;
+ double jitterBufferDelay;
+ unsigned long long jitterBufferEmittedCount;
+ unsigned long long totalSamplesReceived;
+ unsigned long long samplesDecodedWithSilk;
+ unsigned long long samplesDecodedWithCelt;
+ unsigned long long concealedSamples;
+ unsigned long long silentConcealedSamples;
+ unsigned long long concealmentEvents;
+ unsigned long long insertedSamplesForDeceleration;
+ unsigned long long removedSamplesForAcceleration;
+ double audioLevel;
+ double totalAudioEnergy;
+ double totalSamplesDuration;
+ unsigned long framesReceived;
+ DOMString decoderImplementation;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCInboundRtpStreamStats, with all required attributes from its inherited
+ dictionaries, and also attributes receiverId, remoteId, framesDecoded, nackCount, framesReceived, bytesReceived, totalAudioEnergy, totalSampleDuration
+ */
+function validateInboundRtpStreamStats(statsReport, stats) {
+ validateReceivedRtpStreamStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+ validateIdField(statsReport, stats, 'receiverId', 'receiver');
+ validateIdField(statsReport, stats, 'remoteId', 'remote-outbound-rtp');
+ assert_unsigned_int_field(stats, 'framesDecoded');
+ assert_optional_unsigned_int_field(stats, 'keyFramesDecoded');
+ assert_optional_unsigned_int_field(stats, 'frameWidth');
+ assert_optional_unsigned_int_field(stats, 'frameHeight');
+ assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+ assert_optional_number_field(stats, 'framesPerSecond');
+ assert_optional_unsigned_int_field(stats, 'qpSum');
+ assert_optional_number_field(stats, 'totalDecodeTime');
+ assert_optional_number_field(stats, 'totalInterFrameDelay');
+ assert_optional_number_field(stats, 'totalSquaredInterFrameDelay');
+
+ assert_optional_boolean_field(stats, 'voiceActivityFlag');
+
+ assert_optional_number_field(stats, 'lastPacketReceivedTimeStamp');
+ assert_optional_number_field(stats, 'averageRtcpInterval');
+
+ assert_optional_unsigned_int_field(stats, 'fecPacketsReceived');
+ assert_optional_unsigned_int_field(stats, 'fecPacketsDiscarded');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+ assert_optional_unsigned_int_field(stats, 'packetsFailedDecryption');
+ assert_optional_unsigned_int_field(stats, 'packetsDuplicated');
+
+ assert_optional_dict_field(stats, 'perDscpPacketsReceived');
+ if (stats['perDscpPacketsReceived']) {
+ Object.keys(stats['perDscpPacketsReceived'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsReceived to be strings')
+ );
+ Object.values(stats['perDscpPacketsReceived'])
+ .forEach(v =>
+ assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsReceived to be strings')
+ );
+ }
+
+ assert_unsigned_int_field(stats, 'nackCount');
+
+ assert_optional_unsigned_int_field(stats, 'firCount');
+ assert_optional_unsigned_int_field(stats, 'pliCount');
+ assert_optional_unsigned_int_field(stats, 'sliCount');
+
+ assert_optional_number_field(stats, 'estimatedPlayoutTimestamp');
+ assert_optional_number_field(stats, 'jitterBufferDelay');
+ assert_optional_unsigned_int_field(stats, 'jitterBufferEmittedCount');
+ assert_optional_unsigned_int_field(stats, 'totalSamplesReceived');
+ assert_optional_unsigned_int_field(stats, 'samplesDecodedWithSilk');
+ assert_optional_unsigned_int_field(stats, 'samplesDecodedWithCelt');
+ assert_optional_unsigned_int_field(stats, 'concealedSamples');
+ assert_optional_unsigned_int_field(stats, 'silentConcealedSamples');
+ assert_optional_unsigned_int_field(stats, 'concealmentEvents');
+ assert_optional_unsigned_int_field(stats, 'insertedSamplesForDeceleration');
+ assert_optional_unsigned_int_field(stats, 'removedSamplesForAcceleration');
+ assert_optional_number_field(stats, 'audioLevel');
+ assert_optional_number_field(stats, 'totalAudioEnergy');
+ assert_optional_number_field(stats, 'totalSamplesDuration');
+ assert_unsigned_int_field(stats, 'framesReceived');
+ assert_optional_string_field(stats, 'decoderImplementation');
+}
+
+/*
+ [webrtc-stats]
+ 7.5. RTCRemoteInboundRtpStreamStats dictionary
+ dictionary RTCRemoteInboundRtpStreamStats : RTCReceivedRtpStreamStats {
+ DOMString localId;
+ double roundTripTime;
+ double totalRoundTripTime;
+ double fractionLost;
+ unsigned long long reportsReceived;
+ unsigned long long roundTripTimeMeasurements;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRemoteInboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes localId, roundTripTime
+ */
+function validateRemoteInboundRtpStreamStats(statsReport, stats) {
+ validateReceivedRtpStreamStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'localId', 'outbound-rtp');
+ assert_number_field(stats, 'roundTripTime');
+ assert_optional_number_field(stats, 'totalRoundTripTime');
+ assert_optional_number_field(stats, 'fractionLost');
+ assert_optional_unsigned_int_field(stats, 'reportsReceived');
+ assert_optional_unsigned_int_field(stats, 'roundTripTimeMeasurements');
+}
+
+/*
+ [webrtc-stats]
+ 7.6. RTCSentRtpStreamStats dictionary
+ dictionary RTCSentRtpStreamStats : RTCRtpStreamStats {
+ unsigned long packetsSent;
+ unsigned long long bytesSent;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCSentRtpStreamStats, with all required attributes from its inherited
+ dictionaries, and also attributes packetsSent, bytesSent
+ */
+function validateSentRtpStreamStats(statsReport, stats) {
+ validateRtpStreamStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'packetsSent');
+ assert_unsigned_int_field(stats, 'bytesSent');
+}
+
+/*
+ [webrtc-stats]
+ 7.7. RTCOutboundRtpStreamStats dictionary
+ dictionary RTCOutboundRtpStreamStats : RTCSentRtpStreamStats {
+ DOMString mediaSourceId;
+ DOMString senderId;
+ DOMString remoteId;
+ DOMString rid;
+ DOMHighResTimeStamp lastPacketSentTimestamp;
+ unsigned long long headerBytesSent;
+ unsigned long packetsDiscardedOnSend;
+ unsigned long long bytesDiscardedOnSend;
+ unsigned long fecPacketsSent;
+ unsigned long long retransmittedPacketsSent;
+ unsigned long long retransmittedBytesSent;
+ double targetBitrate;
+ unsigned long long totalEncodedBytesTarget;
+ unsigned long frameWidth;
+ unsigned long frameHeight;
+ unsigned long frameBitDepth;
+ double framesPerSecond;
+ unsigned long framesSent;
+ unsigned long hugeFramesSent;
+ unsigned long framesEncoded;
+ unsigned long keyFramesEncoded;
+ unsigned long framesDiscardedOnSend;
+ unsigned long long qpSum;
+ unsigned long long totalSamplesSent;
+ unsigned long long samplesEncodedWithSilk;
+ unsigned long long samplesEncodedWithCelt;
+ boolean voiceActivityFlag;
+ double totalEncodeTime;
+ double totalPacketSendDelay;
+ double averageRtcpInterval;
+ RTCQualityLimitationReason qualityLimitationReason;
+ record<DOMString, double> qualityLimitationDurations;
+ unsigned long qualityLimitationResolutionChanges;
+ record<USVString, unsigned long long> perDscpPacketsSent;
+ unsigned long nackCount;
+ unsigned long firCount;
+ unsigned long pliCount;
+ unsigned long sliCount;
+ DOMString encoderImplementation;
+ };
+ Obsolete members:
+ partial dictionary RTCOutboundStreamStats {
+ DOMString trackId;
+ };
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCOutboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes senderId, remoteId, framesEncoded, nackCount, framesSent
+ */
+function validateOutboundRtpStreamStats(statsReport, stats) {
+ validateSentRtpStreamStats(statsReport, stats)
+
+ validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+ validateIdField(statsReport, stats, 'senderId', 'sender');
+ validateIdField(statsReport, stats, 'remoteId', 'remote-inbound-rtp');
+
+ assert_optional_string_field(stats, 'rid');
+
+ assert_optional_number_field(stats, 'lastPacketSentTimestamp');
+ assert_optional_unsigned_int_field(stats, 'headerBytesSent');
+ assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'fecPacketsSent');
+ assert_optional_unsigned_int_field(stats, 'retransmittedPacketsSent');
+ assert_optional_unsigned_int_field(stats, 'retransmittedBytesSent');
+ assert_optional_number_field(stats, 'targetBitrate');
+ assert_optional_unsigned_int_field(stats, 'totalEncodedBytesTarget');
+ if (stats['kind'] === 'video') {
+ assert_optional_unsigned_int_field(stats, 'frameWidth');
+ assert_optional_unsigned_int_field(stats, 'frameHeight');
+ assert_optional_unsigned_int_field(stats, 'frameBitDepth');
+ assert_optional_number_field(stats, 'framesPerSecond');
+ assert_unsigned_int_field(stats, 'framesSent');
+ assert_optional_unsigned_int_field(stats, 'hugeFramesSent');
+ assert_unsigned_int_field(stats, 'framesEncoded');
+ assert_optional_unsigned_int_field(stats, 'keyFramesEncoded');
+ assert_optional_unsigned_int_field(stats, 'framesDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'qpSum');
+ } else if (stats['kind'] === 'audio') {
+ assert_optional_unsigned_int_field(stats, 'totalSamplesSent');
+ assert_optional_unsigned_int_field(stats, 'samplesEncodedWithSilk');
+ assert_optional_unsigned_int_field(stats, 'samplesEncodedWithCelt');
+ assert_optional_boolean_field(stats, 'voiceActivityFlag');
+ }
+ assert_optional_number_field(stats, 'totalEncodeTime');
+ assert_optional_number_field(stats, 'totalPacketSendDelay');
+ assert_optional_number_field(stats, 'averageRTCPInterval');
+
+ if (stats['kind'] === 'video') {
+ assert_optional_enum_field(stats, 'qualityLimitationReason', ['none', 'cpu', 'bandwidth', 'other']);
+
+ assert_optional_dict_field(stats, 'qualityLimitationDurations');
+ if (stats['qualityLimitationDurations']) {
+ Object.keys(stats['qualityLimitationDurations'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of qualityLimitationDurations to be strings')
+ );
+ Object.values(stats['qualityLimitationDurations'])
+ .forEach(v =>
+ assert_equals(typeof num, 'number', 'Expect values of qualityLimitationDurations to be numbers')
+ );
+ }
+
+ assert_optional_unsigned_int_field(stats, 'qualityLimitationResolutionChanges');
+ }
+ assert_unsigned_int_field(stats, 'nackCount');
+ assert_optional_dict_field(stats, 'perDscpPacketsSent');
+ if (stats['perDscpPacketsSent']) {
+ Object.keys(stats['perDscpPacketsSent'])
+ .forEach(k =>
+ assert_equals(typeof k, 'string', 'Expect keys of perDscpPacketsSent to be strings')
+ );
+ Object.values(stats['perDscpPacketsSent'])
+ .forEach(v =>
+ assert_true(Number.isInteger(v) && (v >= 0), 'Expect values of perDscpPacketsSent to be strings')
+ );
+ }
+
+ assert_optional_unsigned_int_field(stats, 'firCount');
+ assert_optional_unsigned_int_field(stats, 'pliCount');
+ assert_optional_unsigned_int_field(stats, 'sliCount');
+ assert_optional_string_field(stats, 'encoderImplementation');
+ // Obsolete stats
+ validateOptionalIdField(statsReport, stats, 'trackId', 'track');
+}
+
+/*
+ [webrtc-stats]
+ 7.8. RTCRemoteOutboundRtpStreamStats dictionary
+ dictionary RTCRemoteOutboundRtpStreamStats : RTCSentRtpStreamStats {
+ DOMString localId;
+ DOMHighResTimeStamp remoteTimestamp;
+ unsigned long long reportsSent;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCRemoteOutboundRtpStreamStats, with all required attributes from its
+ inherited dictionaries, and also attributes localId, remoteTimestamp
+ */
+function validateRemoteOutboundRtpStreamStats(statsReport, stats) {
+ validateSentRtpStreamStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'localId', 'inbound-rtp');
+ assert_number_field(stats, 'remoteTimeStamp');
+ assert_optional_unsigned_int_field(stats, 'reportsSent');
+}
+
+/*
+ [webrtc-stats]
+ 7.11 RTCMediaSourceStats dictionary
+ dictionary RTCMediaSourceStats : RTCStats {
+ DOMString trackIdentifier;
+ DOMString kind;
+ };
+
+ dictionary RTCAudioSourceStats : RTCMediaSourceStats {
+ double audioLevel;
+ double totalAudioEnergy;
+ double totalSamplesDuration;
+ double echoReturnLoss;
+ double echoReturnLossEnhancement;
+ };
+
+ dictionary RTCVideoSourceStats : RTCMediaSourceStats {
+ unsigned long width;
+ unsigned long height;
+ unsigned long bitDepth;
+ unsigned long frames;
+ // see https://github.com/w3c/webrtc-stats/issues/540
+ double framesPerSecond;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ RTCMediaSourceStats with attributes trackIdentifier, kind
+ RTCAudioSourceStats, with all required attributes from its inherited dictionaries and totalAudioEnergy, totalSamplesDuration
+ RTCVideoSourceStats, with all required attributes from its inherited dictionaries and width, height, framesPerSecond
+*/
+function validateMediaSourceStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ assert_string_field(stats, 'trackIdentifier');
+ assert_enum_field(stats, 'kind', ['audio', 'video']);
+
+ if (stats.kind === 'audio') {
+ assert_optional_number_field(stats, 'audioLevel');
+ assert_number_field(stats, 'totalAudioEnergy');
+ assert_number_field(stats, 'totalSamplesDuration');
+ assert_optional_number_field(stats, 'echoReturnLoss');
+ assert_optional_number_field(stats, 'echoReturnLossEnhancement');
+ } else if (stats.kind === 'video') {
+ assert_unsigned_int_field(stats, 'width');
+ assert_unsigned_int_field(stats, 'height');
+ assert_optional_unsigned_int_field(stats, 'bitDpeth');
+ assert_optional_unsigned_int_field(stats, 'frames');
+ assert_number_field(stats, 'framesPerSecond');
+ }
+}
+
+/*
+ [webrtc-stats]
+ 7.9. RTCRTPContributingSourceStats
+ dictionary RTCRTPContributingSourceStats : RTCStats {
+ unsigned long contributorSsrc;
+ DOMString inboundRtpStreamId;
+ unsigned long packetsContributedTo;
+ double audioLevel;
+ };
+ */
+function validateContributingSourceStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_unsigned_int_field(stats, 'contributorSsrc');
+
+ validateOptionalIdField(statsReport, stats, 'inboundRtpStreamId', 'inbound-rtp');
+ assert_optional_unsigned_int_field(stats, 'packetsContributedTo');
+ assert_optional_number_field(stats, 'audioLevel');
+}
+
+/*
+ [webrtc-stats]
+ 7.10. RTCPeerConnectionStats dictionary
+ dictionary RTCPeerConnectionStats : RTCStats {
+ unsigned long dataChannelsOpened;
+ unsigned long dataChannelsClosed;
+ unsigned long dataChannelsRequested;
+ unsigned long dataChannelsAccepted;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCPeerConnectionStats, with attributes dataChannelsOpened, dataChannelsClosed
+ */
+function validatePeerConnectionStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_unsigned_int_field(stats, 'dataChannelsOpened');
+ assert_unsigned_int_field(stats, 'dataChannelsClosed');
+ assert_optional_unsigned_int_field(stats, 'dataChannelsRequested');
+ assert_optional_unsigned_int_field(stats, 'dataChannelsAccepted');
+}
+
+/* [webrtc-stats]
+ 7.16 RTCRtpTransceiverStats dictionary
+ dictionary RTCRtpTransceiverStats {
+ DOMString senderId;
+ DOMString receiverId;
+ DOMString mid;
+ };
+*/
+function validateTransceiverStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'senderId', 'sender');
+ validateOptionalIdField(statsReport, stats, 'receiverId', 'sender');
+ assert_optional_string_field(stats, 'mid');
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCMediaHandlerStats : RTCStats {
+ DOMString trackIdentifier;
+ boolean remoteSource;
+ boolean ended;
+ DOMString kind;
+ RTCPriorityType priority;
+ };
+ dictionary RTCVideoHandlerStats : RTCMediaHandlerStats {
+ };
+ dictionary RTCAudioHandlerStats : RTCMediaHandlerStats {
+ };
+ Used from validateSenderStats and validateReceiverStats
+
+ [webrtc-priority]
+ enum RTCPriorityType {
+ "very-low",
+ "low",
+ "medium",
+ "high"
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCMediaHandlerStats with attributes trackIdentifier
+ RTCAudioHandlerStats, with all required attributes from its inherited dictionaries
+ RTCVideoHandlerStats, with all required attributes from its inherited dictionaries
+
+*/
+function validateMediaHandlerStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+ assert_string_field(stats, 'trackIdentifier');
+ assert_optional_boolean_field(stats, 'remoteSource');
+ assert_optional_boolean_field(stats, 'ended');
+ assert_optional_string_field(stats, 'kind');
+ assert_enum_field(stats, 'priority', ['very-low', 'low', 'medium', 'high']);
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCAudioSenderStats : RTCAudioHandlerStats {
+ DOMString mediaSourceId;
+ };
+ dictionary RTCVideoSenderStats : RTCVideoHandlerStats {
+ DOMString mediaSourceId;
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCVideoSenderStats, with all required attributes from its inherited dictionaries
+*/
+function validateSenderStats(statsReport, stats) {
+ validateMediaHandlerStats(statsReport, stats);
+ validateOptionalIdField(statsReport, stats, 'mediaSourceId', 'media-source');
+}
+
+/*
+ [webrtc-stats]
+ dictionary RTCAudioReceiverStats : RTCAudioHandlerStats {
+ };
+ dictionary RTCVideoReceiverStats : RTCVideoHandlerStats {
+ };
+
+ [webrtc-pc]
+ MTI:
+ RTCVideoReceiverStats, with all required attributes from its inherited dictionaries
+*/
+function validateReceiverStats(statsReport, stats) {
+ validateMediaHandlerStats(statsReport, stats);
+}
+
+
+/*
+ [webrtc-stats]
+ 7.13. RTCDataChannelStats dictionary
+ dictionary RTCDataChannelStats : RTCStats {
+ DOMString label;
+ DOMString protocol;
+ // see https://github.com/w3c/webrtc-stats/issues/541
+ unsigned short dataChannelIdentifier;
+ DOMString transportId;
+ RTCDataChannelState state;
+ unsigned long messagesSent;
+ unsigned long long bytesSent;
+ unsigned long messagesReceived;
+ unsigned long long bytesReceived;
+ };
+
+ [webrtc-pc]
+ 6.2. RTCDataChannel
+ enum RTCDataChannelState {
+ "connecting",
+ "open",
+ "closing",
+ "closed"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCDataChannelStats, with attributes label, protocol, datachannelIdentifier, state,
+ messagesSent, bytesSent, messagesReceived, bytesReceived
+ */
+function validateDataChannelStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_string_field(stats, 'label');
+ assert_string_field(stats, 'protocol');
+ assert_unsigned_int_field(stats, 'dataChannelIdentifier');
+
+ validateOptionalIdField(statsReport, stats, 'transportId', 'transport');
+
+ assert_enum_field(stats, 'state',
+ ['connecting', 'open', 'closing', 'closed']);
+
+ assert_unsigned_int_field(stats, 'messagesSent');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'messagesReceived');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+}
+
+/*
+ [webrtc-stats]
+ 7.14. RTCTransportStats dictionary
+ dictionary RTCTransportStats : RTCStats {
+ unsigned long long packetsSent;
+ unsigned long long packetsReceived;
+ unsigned long long bytesSent;
+ unsigned long long bytesReceived;
+ DOMString rtcpTransportStatsId;
+ RTCIceRole iceRole;
+ RTCDtlsTransportState dtlsState;
+ DOMString selectedCandidatePairId;
+ DOMString localCertificateId;
+ DOMString remoteCertificateId;
+ DOMString tlsVersion;
+ DOMString dtlsCipher;
+ DOMString srtpCipher;
+ DOMString tlsGroup;
+ unsigned long selectedCandidatePairChanges;
+ };
+
+ [webrtc-pc]
+ 5.5. RTCDtlsTransportState Enum
+ enum RTCDtlsTransportState {
+ "new",
+ "connecting",
+ "connected",
+ "closed",
+ "failed"
+ };
+
+ 5.6. RTCIceRole Enum
+ enum RTCIceRole {
+ "unknown",
+ "controlling",
+ "controlled"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCTransportStats, with attributes bytesSent, bytesReceived,
+ selectedCandidatePairId, localCertificateId,
+ remoteCertificateId
+ */
+function validateTransportStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_unsigned_int_field(stats, 'packetsSent');
+ assert_optional_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+
+ validateOptionalIdField(statsReport, stats, 'rtcpTransportStatsId',
+ 'transport');
+
+ assert_optional_enum_field(stats, 'iceRole',
+ ['unknown', 'controlling', 'controlled']);
+
+ assert_optional_enum_field(stats, 'dtlsState',
+ ['new', 'connecting', 'connected', 'closed', 'failed']);
+
+ validateIdField(statsReport, stats, 'selectedCandidatePairId', 'candidate-pair');
+ validateIdField(statsReport, stats, 'localCertificateId', 'certificate');
+ validateIdField(statsReport, stats, 'remoteCertificateId', 'certificate');
+ assert_optional_string_field(stats, 'tlsVersion');
+ assert_optional_string_field(stats, 'dtlsCipher');
+ assert_optional_string_field(stats, 'srtpCipher');
+ assert_optional_string_field(stats, 'tlsGroup');
+ assert_optional_unsigned_int_field(stats, 'selectedCandidatePairChanges');
+}
+
+/*
+ [webrtc-stats]
+ 7.15. RTCIceCandidateStats dictionary
+ dictionary RTCIceCandidateStats : RTCStats {
+ required DOMString transportId;
+ DOMString? address;
+ long port;
+ DOMString protocol;
+ RTCIceCandidateType candidateType;
+ long priority;
+ DOMString url;
+ DOMString relayProtocol;
+ };
+
+ [webrtc-pc]
+ 4.8.1.3. RTCIceCandidateType Enum
+ enum RTCIceCandidateType {
+ "host",
+ "srflx",
+ "prflx",
+ "relay"
+ };
+
+ 8.6. Mandatory To Implement Stats
+ - RTCIceCandidateStats, with attributes address, port, protocol, candidateType, url
+ */
+function validateIceCandidateStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ // The address is mandatory to implement, but is allowed to be null
+ // when hidden for privacy reasons.
+ if (stats.address != null) {
+ // Departure from strict spec reading:
+ // This field is populated in a racy manner in Chrome.
+ // We allow it to be present or not present for the time being.
+ // TODO(https://bugs.chromium.org/1092721): Become consistent.
+ assert_optional_string_field(stats, 'address');
+ }
+ assert_unsigned_int_field(stats, 'port');
+ assert_string_field(stats, 'protocol');
+
+ assert_enum_field(stats, 'candidateType',
+ ['host', 'srflx', 'prflx', 'relay']);
+
+ assert_optional_int_field(stats, 'priority');
+ // The url field is mandatory for local candidates gathered from
+ // a STUN or TURN server, and MUST NOT be present otherwise.
+ // TODO(hta): Improve checking.
+ assert_optional_string_field(stats, 'url');
+ assert_optional_string_field(stats, 'relayProtocol');
+}
+
+/*
+ [webrtc-stats]
+ 7.16. RTCIceCandidatePairStats dictionary
+ dictionary RTCIceCandidatePairStats : RTCStats {
+ DOMString transportId;
+ DOMString localCandidateId;
+ DOMString remoteCandidateId;
+ RTCStatsIceCandidatePairState state;
+ boolean nominated;
+ unsigned long packetsSent;
+ unsigned long packetsReceived;
+ unsigned long long bytesSent;
+ unsigned long long bytesReceived;
+ DOMHighResTimeStamp lastPacketSentTimestamp;
+ DOMHighResTimeStamp lastPacketReceivedTimestamp;
+ DOMHighResTimeStamp firstRequestTimestamp;
+ DOMHighResTimeStamp lastRequestTimestamp;
+ DOMHighResTimeStamp lastResponseTimestamp;
+ double totalRoundTripTime;
+ double currentRoundTripTime;
+ double availableOutgoingBitrate;
+ double availableIncomingBitrate;
+ unsigned long circuitBreakerTriggerCount;
+ unsigned long long requestsReceived;
+ unsigned long long requestsSent;
+ unsigned long long responsesReceived;
+ unsigned long long responsesSent;
+ unsigned long long retransmissionsReceived;
+ unsigned long long retransmissionsSent;
+ unsigned long long consentRequestsSent;
+ DOMHighResTimeStamp consentExpiredTimestamp;
+ unsigned long packetsDiscardedOnSend;
+ unsigned long long bytesDiscardedOnSend; };
+
+ enum RTCStatsIceCandidatePairState {
+ "frozen",
+ "waiting",
+ "in-progress",
+ "failed",
+ "succeeded"
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCIceCandidatePairStats, with attributes transportId, localCandidateId,
+ remoteCandidateId, state, nominated, bytesSent, bytesReceived, totalRoundTripTime, currentRoundTripTime
+ // not including priority per https://github.com/w3c/webrtc-pc/issues/2457
+ */
+function validateIceCandidatePairStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ validateIdField(statsReport, stats, 'transportId', 'transport');
+ validateIdField(statsReport, stats, 'localCandidateId', 'local-candidate');
+ validateIdField(statsReport, stats, 'remoteCandidateId', 'remote-candidate');
+
+ assert_enum_field(stats, 'state',
+ ['frozen', 'waiting', 'in-progress', 'failed', 'succeeded']);
+
+ assert_boolean_field(stats, 'nominated');
+ assert_optional_unsigned_int_field(stats, 'packetsSent');
+ assert_optional_unsigned_int_field(stats, 'packetsReceived');
+ assert_unsigned_int_field(stats, 'bytesSent');
+ assert_unsigned_int_field(stats, 'bytesReceived');
+
+ assert_optional_number_field(stats, 'lastPacketSentTimestamp');
+ assert_optional_number_field(stats, 'lastPacketReceivedTimestamp');
+ assert_optional_number_field(stats, 'firstRequestTimestamp');
+ assert_optional_number_field(stats, 'lastRequestTimestamp');
+ assert_optional_number_field(stats, 'lastResponseTimestamp');
+
+ assert_number_field(stats, 'totalRoundTripTime');
+ assert_number_field(stats, 'currentRoundTripTime');
+
+ assert_optional_number_field(stats, 'availableOutgoingBitrate');
+ assert_optional_number_field(stats, 'availableIncomingBitrate');
+
+ assert_optional_unsigned_int_field(stats, 'circuitBreakerTriggerCount');
+ assert_optional_unsigned_int_field(stats, 'requestsReceived');
+ assert_optional_unsigned_int_field(stats, 'requestsSent');
+ assert_optional_unsigned_int_field(stats, 'responsesReceived');
+ assert_optional_unsigned_int_field(stats, 'responsesSent');
+ assert_optional_unsigned_int_field(stats, 'retransmissionsReceived');
+ assert_optional_unsigned_int_field(stats, 'retransmissionsSent');
+ assert_optional_unsigned_int_field(stats, 'consentRequestsSent');
+ assert_optional_number_field(stats, 'consentExpiredTimestamp');
+ assert_optional_unsigned_int_field(stats, 'packetsDiscardedOnSend');
+ assert_optional_unsigned_int_field(stats, 'bytesDiscardedOnSend');
+}
+
+/*
+ [webrtc-stats]
+ 7.17. RTCCertificateStats dictionary
+ dictionary RTCCertificateStats : RTCStats {
+ DOMString fingerprint;
+ DOMString fingerprintAlgorithm;
+ DOMString base64Certificate;
+ DOMString issuerCertificateId;
+ };
+
+ [webrtc-pc]
+ 8.6. Mandatory To Implement Stats
+ - RTCCertificateStats, with attributes fingerprint, fingerprintAlgorithm,
+ base64Certificate, issuerCertificateId
+ */
+function validateCertificateStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_string_field(stats, 'fingerprint');
+ assert_string_field(stats, 'fingerprintAlgorithm');
+ assert_string_field(stats, 'base64Certificate');
+ assert_optional_string_field(stats, 'issuerCertificateId');
+}
+
+/*
+ [webrtc-stats]
+ 7.30. RTCIceServerStats dictionary
+ dictionary RTCIceServerStats : RTCStats {
+ DOMString url;
+ long port;
+ DOMString protocol;
+ unsigned long totalRequestsSent;
+ unsigned long totalResponsesReceived;
+ double totalRoundTripTime;
+ };
+*/
+function validateIceServerStats(statsReport, stats) {
+ validateRtcStats(statsReport, stats);
+
+ assert_optional_string_field(stats, 'url');
+ assert_optional_int_field(stats, 'port');
+ assert_optional_string_field(stats, 'protocol');
+ assert_optional_unsigned_int_field(stats, 'totalRequestsSent');
+ assert_optional_unsigned_int_field(stats, 'totalResponsesReceived');
+ assert_optional_number_field(stats, 'totalRoundTripTime');
+}
--- /dev/null
+'use strict';
+
+// Helper assertion functions to validate dictionary fields
+// on dictionary objects returned from APIs
+
+function assert_unsigned_int_field(object, field) {
+ const num = object[field];
+ assert_true(Number.isInteger(num) && (num >= 0),
+ `Expect dictionary.${field} to be unsigned integer`);
+}
+
+function assert_int_field(object, field) {
+ const num = object[field];
+ assert_true(Number.isInteger(num),
+ `Expect dictionary.${field} to be integer`);
+}
+
+function assert_string_field(object, field) {
+ const str = object[field];
+ assert_equals(typeof str, 'string',
+ `Expect dictionary.${field} to be string`);
+}
+
+function assert_number_field(object, field) {
+ const num = object[field];
+ assert_equals(typeof num, 'number',
+ `Expect dictionary.${field} to be number`);
+}
+
+function assert_boolean_field(object, field) {
+ const bool = object[field];
+ assert_equals(typeof bool, 'boolean',
+ `Expect dictionary.${field} to be boolean`);
+}
+
+function assert_array_field(object, field) {
+ assert_true(Array.isArray(object[field]),
+ `Expect dictionary.${field} to be array`);
+}
+
+function assert_dict_field(object, field) {
+ assert_equals(typeof object[field], 'object',
+ `Expect dictionary.${field} to be plain object`);
+
+ assert_not_equals(object[field], null,
+ `Expect dictionary.${field} to not be null`);
+}
+
+function assert_enum_field(object, field, validValues) {
+ assert_string_field(object, field);
+ assert_true(validValues.includes(object[field]),
+ `Expect dictionary.${field} to have one of the valid enum values: ${validValues}`);
+}
+
+function assert_optional_unsigned_int_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_unsigned_int_field(object, field);
+ }
+}
+
+function assert_optional_int_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_int_field(object, field);
+ }
+}
+
+function assert_optional_string_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_string_field(object, field);
+ }
+}
+
+function assert_optional_number_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_number_field(object, field);
+ }
+}
+
+function assert_optional_boolean_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_boolean_field(object, field);
+ }
+}
+
+function assert_optional_array_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_array_field(object, field);
+ }
+}
+
+function assert_optional_dict_field(object, field) {
+ if(object[field] !== undefined) {
+ assert_dict_field(object, field);
+ }
+}
+
+function assert_optional_enum_field(object, field, validValues) {
+ if(object[field] !== undefined) {
+ assert_enum_field(object, field, validValues);
+ }
+}
--- /dev/null
+/**
+ * Host information for cross-origin tests.
+ * @returns {Object} with properties for different host information.
+ */
+function get_host_info() {
+
+ var HTTP_PORT = '8000';
+ var HTTP_PORT2 = '81';
+ var HTTPS_PORT = '443';
+ var HTTPS_PORT2 = '444';
+ var PROTOCOL = self.location.protocol;
+ var IS_HTTPS = (PROTOCOL == "https:");
+ var PORT = IS_HTTPS ? HTTPS_PORT : HTTP_PORT;
+ var PORT2 = IS_HTTPS ? HTTPS_PORT2 : HTTP_PORT2;
+ var HTTP_PORT_ELIDED = HTTP_PORT == "80" ? "" : (":" + HTTP_PORT);
+ var HTTP_PORT2_ELIDED = HTTP_PORT2 == "80" ? "" : (":" + HTTP_PORT2);
+ var HTTPS_PORT_ELIDED = HTTPS_PORT == "443" ? "" : (":" + HTTPS_PORT);
+ var PORT_ELIDED = IS_HTTPS ? HTTPS_PORT_ELIDED : HTTP_PORT_ELIDED;
+ var ORIGINAL_HOST = 'w3c-test.org';
+ var REMOTE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('www.' + ORIGINAL_HOST);
+ var OTHER_HOST = 'www2.w3c-test.org';
+ var NOTSAMESITE_HOST = (ORIGINAL_HOST === 'localhost') ? '127.0.0.1' : ('not-web-platform.test');
+
+ return {
+ HTTP_PORT: HTTP_PORT,
+ HTTP_PORT2: HTTP_PORT2,
+ HTTPS_PORT: HTTPS_PORT,
+ HTTPS_PORT2: HTTPS_PORT2,
+ PORT: PORT,
+ PORT2: PORT2,
+ ORIGINAL_HOST: ORIGINAL_HOST,
+ REMOTE_HOST: REMOTE_HOST,
+
+ ORIGIN: PROTOCOL + "//" + ORIGINAL_HOST + PORT_ELIDED,
+ HTTP_ORIGIN: 'http://' + ORIGINAL_HOST + HTTP_PORT_ELIDED,
+ HTTPS_ORIGIN: 'https://' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_ORIGIN_WITH_CREDS: 'https://foo:bar@' + ORIGINAL_HOST + HTTPS_PORT_ELIDED,
+ HTTP_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + ORIGINAL_HOST + HTTP_PORT2_ELIDED,
+ REMOTE_ORIGIN: PROTOCOL + "//" + REMOTE_HOST + PORT_ELIDED,
+ OTHER_ORIGIN: PROTOCOL + "//" + OTHER_HOST + PORT_ELIDED,
+ HTTP_REMOTE_ORIGIN: 'http://' + REMOTE_HOST + HTTP_PORT_ELIDED,
+ HTTP_NOTSAMESITE_ORIGIN: 'http://' + NOTSAMESITE_HOST + HTTP_PORT_ELIDED,
+ HTTP_REMOTE_ORIGIN_WITH_DIFFERENT_PORT: 'http://' + REMOTE_HOST + HTTP_PORT2_ELIDED,
+ HTTPS_REMOTE_ORIGIN: 'https://' + REMOTE_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_REMOTE_ORIGIN_WITH_CREDS: 'https://foo:bar@' + REMOTE_HOST + HTTPS_PORT_ELIDED,
+ HTTPS_NOTSAMESITE_ORIGIN: 'https://' + NOTSAMESITE_HOST + HTTPS_PORT_ELIDED,
+ UNAUTHENTICATED_ORIGIN: 'http://' + OTHER_HOST + HTTP_PORT_ELIDED,
+ AUTHENTICATED_ORIGIN: 'https://' + OTHER_HOST + HTTPS_PORT_ELIDED
+ };
+}
+
+/**
+ * When a default port is used, location.port returns the empty string.
+ * This function attempts to provide an exact port, assuming we are running under wptserve.
+ * @param {*} loc - can be Location/<a>/<area>/URL, but assumes http/https only.
+ * @returns {string} The port number.
+ */
+function get_port(loc) {
+ if (loc.port) {
+ return loc.port;
+ }
+ return loc.protocol === 'https:' ? '443' : '80';
+}
--- /dev/null
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: script=./RTCPeerConnection-helper.js
+// META: timeout=long
+
+'use strict';
+
+// The following helper functions are called from RTCPeerConnection-helper.js:
+// generateAnswer()
+// getNoiseStream()
+
+// Put the global IDL test objects under a parent object.
+// This allows easier search for the test cases when
+// viewing the web page
+const idlTestObjects = {};
+
+// Helper function to create RTCTrackEvent object
+function initTrackEvent() {
+ const pc = new RTCPeerConnection();
+ const transceiver = pc.addTransceiver('audio');
+ const { sender, receiver } = transceiver;
+ const { track } = receiver;
+ return new RTCTrackEvent('track', {
+ receiver, track, transceiver
+ });
+}
+
+// List of async test driver functions
+const asyncInitTasks = [
+ asyncInitCertificate,
+ asyncInitTransports,
+ asyncInitMediaStreamTrack,
+];
+
+// Asynchronously generate an RTCCertificate
+function asyncInitCertificate() {
+ return RTCPeerConnection.generateCertificate({
+ name: 'RSASSA-PKCS1-v1_5',
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([1, 0, 1]),
+ hash: 'SHA-256'
+ }).then(cert => {
+ idlTestObjects.certificate = cert;
+ });
+}
+
+// Asynchronously generate instances of
+// RTCSctpTransport, RTCDtlsTransport,
+// and RTCIceTransport
+function asyncInitTransports() {
+ const pc = new RTCPeerConnection();
+ pc.createDataChannel('test');
+
+ // setting answer description initializes pc.sctp
+ return pc.createOffer()
+ .then(offer =>
+ pc.setLocalDescription(offer)
+ .then(() => generateAnswer(offer)))
+ .then(answer => pc.setRemoteDescription(answer))
+ .then(() => {
+ const sctpTransport = pc.sctp;
+ assert_true(sctpTransport instanceof RTCSctpTransport,
+ 'Expect pc.sctp to be instance of RTCSctpTransport');
+ idlTestObjects.sctpTransport = sctpTransport;
+
+ const dtlsTransport = sctpTransport.transport;
+ assert_true(dtlsTransport instanceof RTCDtlsTransport,
+ 'Expect sctpTransport.transport to be instance of RTCDtlsTransport');
+ idlTestObjects.dtlsTransport = dtlsTransport;
+
+ const iceTransport = dtlsTransport.iceTransport;
+ assert_true(iceTransport instanceof RTCIceTransport,
+ 'Expect sctpTransport.transport to be instance of RTCDtlsTransport');
+ idlTestObjects.iceTransport = iceTransport;
+ });
+}
+
+// Asynchoronously generate MediaStreamTrack from getUserMedia
+function asyncInitMediaStreamTrack() {
+ return getNoiseStream({ audio: true })
+ .then(mediaStream => {
+ idlTestObjects.mediaStreamTrack = mediaStream.getTracks()[0];
+ });
+}
+
+// Run all async test drivers, report and swallow any error
+// thrown/rejected. Proper test for correct initialization
+// of the objects are done in their respective test files.
+function asyncInit() {
+ return Promise.all(asyncInitTasks.map(
+ task => {
+ const t = async_test(`Test driver for ${task.name}`);
+ let promise;
+ t.step(() => {
+ promise = task().then(
+ t.step_func_done(),
+ t.step_func(err =>
+ assert_unreached(`Failed to run ${task.name}: ${err}`)));
+ });
+ return promise;
+ }));
+}
+
+idl_test(
+ ['webrtc'],
+ ['webidl', 'mediacapture-streams', 'hr-time', 'dom', 'html'],
+ async idlArray => {
+ idlArray.add_objects({
+ RTCPeerConnection: [`new RTCPeerConnection()`],
+ RTCSessionDescription: [`new RTCSessionDescription({ type: 'offer' })`],
+ RTCIceCandidate: [`new RTCIceCandidate({ sdpMid: 1 })`],
+ RTCDataChannel: [`new RTCPeerConnection().createDataChannel('')`],
+ RTCRtpTransceiver: [`new RTCPeerConnection().addTransceiver('audio')`],
+ RTCRtpSender: [`new RTCPeerConnection().addTransceiver('audio').sender`],
+ RTCRtpReceiver: [`new RTCPeerConnection().addTransceiver('audio').receiver`],
+ RTCPeerConnectionIceEvent: [`new RTCPeerConnectionIceEvent('ice')`],
+ RTCPeerConnectionIceErrorEvent: [
+ `new RTCPeerConnectionIceErrorEvent('ice-error', { port: 0, errorCode: 701 });`
+ ],
+ RTCTrackEvent: [`initTrackEvent()`],
+ RTCErrorEvent: [`new RTCErrorEvent('error')`],
+ RTCDataChannelEvent: [
+ `new RTCDataChannelEvent('channel', {
+ channel: new RTCPeerConnection().createDataChannel('')
+ })`
+ ],
+ // Async initialized objects below
+ RTCCertificate: ['idlTestObjects.certificate'],
+ RTCSctpTransport: ['idlTestObjects.sctpTransport'],
+ RTCDtlsTransport: ['idlTestObjects.dtlsTransport'],
+ RTCIceTransport: ['idlTestObjects.iceTransport'],
+ MediaStreamTrack: ['idlTestObjects.mediaStreamTrack'],
+ });
+ /*
+ TODO
+ RTCRtpContributingSource
+ RTCRtpSynchronizationSource
+ RTCDTMFSender
+ RTCDTMFToneChangeEvent
+ RTCIdentityProviderRegistrar
+ RTCIdentityAssertion
+ */
+
+ await asyncInit();
+ }
+);
--- /dev/null
+// Set permissions for camera and microphone using Web Driver
+// Status can be one of "granted" or "denied"
+// Scope take values from permission names
+async function setMediaPermission(status="granted", scope=["camera", "microphone"]) {
+ try {
+ for (let s of scope) {
+ await test_driver.set_permission({ name: s }, status, true);
+ }
+ } catch (e) {
+ const noSetPermissionSupport = typeof e === "string" && e.match(/set_permission not implemented/);
+ if (!(noSetPermissionSupport ||
+ (e instanceof Error && e.message.match("unimplemented")) )) {
+ throw e;
+ }
+ // Web Driver not implemented action
+ // FF: https://bugzilla.mozilla.org/show_bug.cgi?id=1524074
+
+ // with current WPT runners, will default to granted state for FF and Safari
+ // throw if status!="granted" to invalidate test results
+ if (status === "denied") {
+ assert_implements_optional(!noSetPermissionSupport, "Unable to set permission to denied for this test");
+ }
+ }
+}
--- /dev/null
+## sdp
+Third-party SDP module from
+ https://www.npmjs.com/package/sdp
+without tests or dependencies. See the commit message for version
+and commit information
--- /dev/null
+Copyright (c) 2017 Philipp Hancke
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+<!doctype html>
+<meta name="viewport" content="width=device-width">
+<title>Directory listing for /webrtc/third_party/sdp/</title>
+<h1>Directory listing for /webrtc/third_party/sdp/</h1>
+<ul>
+<li class="dir"><a href="/webrtc/third_party/">..</a></li>
+<li class="file"><a href="LICENSE">LICENSE</a></li>
+<li class="file"><a href="sdp.js">sdp.js</a></li>
+</ul>
--- /dev/null
+/* eslint-env node */
+'use strict';
+
+// SDP helpers.
+var SDPUtils = {};
+
+// Generate an alphanumeric identifier for cname or mids.
+// TODO: use UUIDs instead? https://gist.github.com/jed/982883
+SDPUtils.generateIdentifier = function() {
+ return Math.random().toString(36).substr(2, 10);
+};
+
+// The RTCP CNAME used by all peerconnections from the same JS.
+SDPUtils.localCName = SDPUtils.generateIdentifier();
+
+// Splits SDP into lines, dealing with both CRLF and LF.
+SDPUtils.splitLines = function(blob) {
+ return blob.trim().split('\n').map(function(line) {
+ return line.trim();
+ });
+};
+// Splits SDP into sessionpart and mediasections. Ensures CRLF.
+SDPUtils.splitSections = function(blob) {
+ var parts = blob.split('\nm=');
+ return parts.map(function(part, index) {
+ return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
+ });
+};
+
+// returns the session description.
+SDPUtils.getDescription = function(blob) {
+ var sections = SDPUtils.splitSections(blob);
+ return sections && sections[0];
+};
+
+// returns the individual media sections.
+SDPUtils.getMediaSections = function(blob) {
+ var sections = SDPUtils.splitSections(blob);
+ sections.shift();
+ return sections;
+};
+
+// Returns lines that start with a certain prefix.
+SDPUtils.matchPrefix = function(blob, prefix) {
+ return SDPUtils.splitLines(blob).filter(function(line) {
+ return line.indexOf(prefix) === 0;
+ });
+};
+
+// Parses an ICE candidate line. Sample input:
+// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8
+// rport 55996"
+SDPUtils.parseCandidate = function(line) {
+ var parts;
+ // Parse both variants.
+ if (line.indexOf('a=candidate:') === 0) {
+ parts = line.substring(12).split(' ');
+ } else {
+ parts = line.substring(10).split(' ');
+ }
+
+ var candidate = {
+ foundation: parts[0],
+ component: parseInt(parts[1], 10),
+ protocol: parts[2].toLowerCase(),
+ priority: parseInt(parts[3], 10),
+ ip: parts[4],
+ address: parts[4], // address is an alias for ip.
+ port: parseInt(parts[5], 10),
+ // skip parts[6] == 'typ'
+ type: parts[7]
+ };
+
+ for (var i = 8; i < parts.length; i += 2) {
+ switch (parts[i]) {
+ case 'raddr':
+ candidate.relatedAddress = parts[i + 1];
+ break;
+ case 'rport':
+ candidate.relatedPort = parseInt(parts[i + 1], 10);
+ break;
+ case 'tcptype':
+ candidate.tcpType = parts[i + 1];
+ break;
+ case 'ufrag':
+ candidate.ufrag = parts[i + 1]; // for backward compability.
+ candidate.usernameFragment = parts[i + 1];
+ break;
+ default: // extension handling, in particular ufrag
+ candidate[parts[i]] = parts[i + 1];
+ break;
+ }
+ }
+ return candidate;
+};
+
+// Translates a candidate object into SDP candidate attribute.
+SDPUtils.writeCandidate = function(candidate) {
+ var sdp = [];
+ sdp.push(candidate.foundation);
+ sdp.push(candidate.component);
+ sdp.push(candidate.protocol.toUpperCase());
+ sdp.push(candidate.priority);
+ sdp.push(candidate.address || candidate.ip);
+ sdp.push(candidate.port);
+
+ var type = candidate.type;
+ sdp.push('typ');
+ sdp.push(type);
+ if (type !== 'host' && candidate.relatedAddress &&
+ candidate.relatedPort) {
+ sdp.push('raddr');
+ sdp.push(candidate.relatedAddress);
+ sdp.push('rport');
+ sdp.push(candidate.relatedPort);
+ }
+ if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') {
+ sdp.push('tcptype');
+ sdp.push(candidate.tcpType);
+ }
+ if (candidate.usernameFragment || candidate.ufrag) {
+ sdp.push('ufrag');
+ sdp.push(candidate.usernameFragment || candidate.ufrag);
+ }
+ return 'candidate:' + sdp.join(' ');
+};
+
+// Parses an ice-options line, returns an array of option tags.
+// a=ice-options:foo bar
+SDPUtils.parseIceOptions = function(line) {
+ return line.substr(14).split(' ');
+};
+
+// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input:
+// a=rtpmap:111 opus/48000/2
+SDPUtils.parseRtpMap = function(line) {
+ var parts = line.substr(9).split(' ');
+ var parsed = {
+ payloadType: parseInt(parts.shift(), 10) // was: id
+ };
+
+ parts = parts[0].split('/');
+
+ parsed.name = parts[0];
+ parsed.clockRate = parseInt(parts[1], 10); // was: clockrate
+ parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1;
+ // legacy alias, got renamed back to channels in ORTC.
+ parsed.numChannels = parsed.channels;
+ return parsed;
+};
+
+// Generate an a=rtpmap line from RTCRtpCodecCapability or
+// RTCRtpCodecParameters.
+SDPUtils.writeRtpMap = function(codec) {
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ var channels = codec.channels || codec.numChannels || 1;
+ return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate +
+ (channels !== 1 ? '/' + channels : '') + '\r\n';
+};
+
+// Parses an a=extmap line (headerextension from RFC 5285). Sample input:
+// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
+// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset
+SDPUtils.parseExtmap = function(line) {
+ var parts = line.substr(9).split(' ');
+ return {
+ id: parseInt(parts[0], 10),
+ direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv',
+ uri: parts[1]
+ };
+};
+
+// Generates a=extmap line from RTCRtpHeaderExtensionParameters or
+// RTCRtpHeaderExtension.
+SDPUtils.writeExtmap = function(headerExtension) {
+ return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) +
+ (headerExtension.direction && headerExtension.direction !== 'sendrecv'
+ ? '/' + headerExtension.direction
+ : '') +
+ ' ' + headerExtension.uri + '\r\n';
+};
+
+// Parses an ftmp line, returns dictionary. Sample input:
+// a=fmtp:96 vbr=on;cng=on
+// Also deals with vbr=on; cng=on
+SDPUtils.parseFmtp = function(line) {
+ var parsed = {};
+ var kv;
+ var parts = line.substr(line.indexOf(' ') + 1).split(';');
+ for (var j = 0; j < parts.length; j++) {
+ kv = parts[j].trim().split('=');
+ parsed[kv[0].trim()] = kv[1];
+ }
+ return parsed;
+};
+
+// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters.
+SDPUtils.writeFmtp = function(codec) {
+ var line = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.parameters && Object.keys(codec.parameters).length) {
+ var params = [];
+ Object.keys(codec.parameters).forEach(function(param) {
+ if (codec.parameters[param]) {
+ params.push(param + '=' + codec.parameters[param]);
+ } else {
+ params.push(param);
+ }
+ });
+ line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n';
+ }
+ return line;
+};
+
+// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input:
+// a=rtcp-fb:98 nack rpsi
+SDPUtils.parseRtcpFb = function(line) {
+ var parts = line.substr(line.indexOf(' ') + 1).split(' ');
+ return {
+ type: parts.shift(),
+ parameter: parts.join(' ')
+ };
+};
+// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters.
+SDPUtils.writeRtcpFb = function(codec) {
+ var lines = '';
+ var pt = codec.payloadType;
+ if (codec.preferredPayloadType !== undefined) {
+ pt = codec.preferredPayloadType;
+ }
+ if (codec.rtcpFeedback && codec.rtcpFeedback.length) {
+ // FIXME: special handling for trr-int?
+ codec.rtcpFeedback.forEach(function(fb) {
+ lines += 'a=rtcp-fb:' + pt + ' ' + fb.type +
+ (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') +
+ '\r\n';
+ });
+ }
+ return lines;
+};
+
+// Parses an RFC 5576 ssrc media attribute. Sample input:
+// a=ssrc:3735928559 cname:something
+SDPUtils.parseSsrcMedia = function(line) {
+ var sp = line.indexOf(' ');
+ var parts = {
+ ssrc: parseInt(line.substr(7, sp - 7), 10)
+ };
+ var colon = line.indexOf(':', sp);
+ if (colon > -1) {
+ parts.attribute = line.substr(sp + 1, colon - sp - 1);
+ parts.value = line.substr(colon + 1);
+ } else {
+ parts.attribute = line.substr(sp + 1);
+ }
+ return parts;
+};
+
+SDPUtils.parseSsrcGroup = function(line) {
+ var parts = line.substr(13).split(' ');
+ return {
+ semantics: parts.shift(),
+ ssrcs: parts.map(function(ssrc) {
+ return parseInt(ssrc, 10);
+ })
+ };
+};
+
+// Extracts the MID (RFC 5888) from a media section.
+// returns the MID or undefined if no mid line was found.
+SDPUtils.getMid = function(mediaSection) {
+ var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0];
+ if (mid) {
+ return mid.substr(6);
+ }
+};
+
+SDPUtils.parseFingerprint = function(line) {
+ var parts = line.substr(14).split(' ');
+ return {
+ algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge.
+ value: parts[1]
+ };
+};
+
+// Extracts DTLS parameters from SDP media section or sessionpart.
+// FIXME: for consistency with other functions this should only
+// get the fingerprint line as input. See also getIceParameters.
+SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
+ 'a=fingerprint:');
+ // Note: a=setup line is ignored since we use the 'auto' role.
+ // Note2: 'algorithm' is not case sensitive except in Edge.
+ return {
+ role: 'auto',
+ fingerprints: lines.map(SDPUtils.parseFingerprint)
+ };
+};
+
+// Serializes DTLS parameters to SDP.
+SDPUtils.writeDtlsParameters = function(params, setupType) {
+ var sdp = 'a=setup:' + setupType + '\r\n';
+ params.fingerprints.forEach(function(fp) {
+ sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n';
+ });
+ return sdp;
+};
+
+// Parses a=crypto lines into
+// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#dictionary-rtcsrtpsdesparameters-members
+SDPUtils.parseCryptoLine = function(line) {
+ var parts = line.substr(9).split(' ');
+ return {
+ tag: parseInt(parts[0], 10),
+ cryptoSuite: parts[1],
+ keyParams: parts[2],
+ sessionParams: parts.slice(3),
+ };
+};
+
+SDPUtils.writeCryptoLine = function(parameters) {
+ return 'a=crypto:' + parameters.tag + ' ' +
+ parameters.cryptoSuite + ' ' +
+ (typeof parameters.keyParams === 'object'
+ ? SDPUtils.writeCryptoKeyParams(parameters.keyParams)
+ : parameters.keyParams) +
+ (parameters.sessionParams ? ' ' + parameters.sessionParams.join(' ') : '') +
+ '\r\n';
+};
+
+// Parses the crypto key parameters into
+// https://rawgit.com/aboba/edgertc/master/msortc-rs4.html#rtcsrtpkeyparam*
+SDPUtils.parseCryptoKeyParams = function(keyParams) {
+ if (keyParams.indexOf('inline:') !== 0) {
+ return null;
+ }
+ var parts = keyParams.substr(7).split('|');
+ return {
+ keyMethod: 'inline',
+ keySalt: parts[0],
+ lifeTime: parts[1],
+ mkiValue: parts[2] ? parts[2].split(':')[0] : undefined,
+ mkiLength: parts[2] ? parts[2].split(':')[1] : undefined,
+ };
+};
+
+SDPUtils.writeCryptoKeyParams = function(keyParams) {
+ return keyParams.keyMethod + ':'
+ + keyParams.keySalt +
+ (keyParams.lifeTime ? '|' + keyParams.lifeTime : '') +
+ (keyParams.mkiValue && keyParams.mkiLength
+ ? '|' + keyParams.mkiValue + ':' + keyParams.mkiLength
+ : '');
+};
+
+// Extracts all SDES paramters.
+SDPUtils.getCryptoParameters = function(mediaSection, sessionpart) {
+ var lines = SDPUtils.matchPrefix(mediaSection + sessionpart,
+ 'a=crypto:');
+ return lines.map(SDPUtils.parseCryptoLine);
+};
+
+// Parses ICE information from SDP media section or sessionpart.
+// FIXME: for consistency with other functions this should only
+// get the ice-ufrag and ice-pwd lines as input.
+SDPUtils.getIceParameters = function(mediaSection, sessionpart) {
+ var ufrag = SDPUtils.matchPrefix(mediaSection + sessionpart,
+ 'a=ice-ufrag:')[0];
+ var pwd = SDPUtils.matchPrefix(mediaSection + sessionpart,
+ 'a=ice-pwd:')[0];
+ if (!(ufrag && pwd)) {
+ return null;
+ }
+ return {
+ usernameFragment: ufrag.substr(12),
+ password: pwd.substr(10),
+ };
+};
+
+// Serializes ICE parameters to SDP.
+SDPUtils.writeIceParameters = function(params) {
+ return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' +
+ 'a=ice-pwd:' + params.password + '\r\n';
+};
+
+// Parses the SDP media section and returns RTCRtpParameters.
+SDPUtils.parseRtpParameters = function(mediaSection) {
+ var description = {
+ codecs: [],
+ headerExtensions: [],
+ fecMechanisms: [],
+ rtcp: []
+ };
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].split(' ');
+ for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..]
+ var pt = mline[i];
+ var rtpmapline = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtpmap:' + pt + ' ')[0];
+ if (rtpmapline) {
+ var codec = SDPUtils.parseRtpMap(rtpmapline);
+ var fmtps = SDPUtils.matchPrefix(
+ mediaSection, 'a=fmtp:' + pt + ' ');
+ // Only the first a=fmtp:<pt> is considered.
+ codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {};
+ codec.rtcpFeedback = SDPUtils.matchPrefix(
+ mediaSection, 'a=rtcp-fb:' + pt + ' ')
+ .map(SDPUtils.parseRtcpFb);
+ description.codecs.push(codec);
+ // parse FEC mechanisms from rtpmap lines.
+ switch (codec.name.toUpperCase()) {
+ case 'RED':
+ case 'ULPFEC':
+ description.fecMechanisms.push(codec.name.toUpperCase());
+ break;
+ default: // only RED and ULPFEC are recognized as FEC mechanisms.
+ break;
+ }
+ }
+ }
+ SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) {
+ description.headerExtensions.push(SDPUtils.parseExtmap(line));
+ });
+ // FIXME: parse rtcp.
+ return description;
+};
+
+// Generates parts of the SDP media section describing the capabilities /
+// parameters.
+SDPUtils.writeRtpDescription = function(kind, caps) {
+ var sdp = '';
+
+ // Build the mline.
+ sdp += 'm=' + kind + ' ';
+ sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs.
+ sdp += ' UDP/TLS/RTP/SAVPF ';
+ sdp += caps.codecs.map(function(codec) {
+ if (codec.preferredPayloadType !== undefined) {
+ return codec.preferredPayloadType;
+ }
+ return codec.payloadType;
+ }).join(' ') + '\r\n';
+
+ sdp += 'c=IN IP4 0.0.0.0\r\n';
+ sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n';
+
+ // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb.
+ caps.codecs.forEach(function(codec) {
+ sdp += SDPUtils.writeRtpMap(codec);
+ sdp += SDPUtils.writeFmtp(codec);
+ sdp += SDPUtils.writeRtcpFb(codec);
+ });
+ var maxptime = 0;
+ caps.codecs.forEach(function(codec) {
+ if (codec.maxptime > maxptime) {
+ maxptime = codec.maxptime;
+ }
+ });
+ if (maxptime > 0) {
+ sdp += 'a=maxptime:' + maxptime + '\r\n';
+ }
+ sdp += 'a=rtcp-mux\r\n';
+
+ if (caps.headerExtensions) {
+ caps.headerExtensions.forEach(function(extension) {
+ sdp += SDPUtils.writeExtmap(extension);
+ });
+ }
+ // FIXME: write fecMechanisms.
+ return sdp;
+};
+
+// Parses the SDP media section and returns an array of
+// RTCRtpEncodingParameters.
+SDPUtils.parseRtpEncodingParameters = function(mediaSection) {
+ var encodingParameters = [];
+ var description = SDPUtils.parseRtpParameters(mediaSection);
+ var hasRed = description.fecMechanisms.indexOf('RED') !== -1;
+ var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1;
+
+ // filter a=ssrc:... cname:, ignore PlanB-msid
+ var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(parts) {
+ return parts.attribute === 'cname';
+ });
+ var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc;
+ var secondarySsrc;
+
+ var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID')
+ .map(function(line) {
+ var parts = line.substr(17).split(' ');
+ return parts.map(function(part) {
+ return parseInt(part, 10);
+ });
+ });
+ if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) {
+ secondarySsrc = flows[0][1];
+ }
+
+ description.codecs.forEach(function(codec) {
+ if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) {
+ var encParam = {
+ ssrc: primarySsrc,
+ codecPayloadType: parseInt(codec.parameters.apt, 10)
+ };
+ if (primarySsrc && secondarySsrc) {
+ encParam.rtx = {ssrc: secondarySsrc};
+ }
+ encodingParameters.push(encParam);
+ if (hasRed) {
+ encParam = JSON.parse(JSON.stringify(encParam));
+ encParam.fec = {
+ ssrc: primarySsrc,
+ mechanism: hasUlpfec ? 'red+ulpfec' : 'red'
+ };
+ encodingParameters.push(encParam);
+ }
+ }
+ });
+ if (encodingParameters.length === 0 && primarySsrc) {
+ encodingParameters.push({
+ ssrc: primarySsrc
+ });
+ }
+
+ // we support both b=AS and b=TIAS but interpret AS as TIAS.
+ var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b=');
+ if (bandwidth.length) {
+ if (bandwidth[0].indexOf('b=TIAS:') === 0) {
+ bandwidth = parseInt(bandwidth[0].substr(7), 10);
+ } else if (bandwidth[0].indexOf('b=AS:') === 0) {
+ // use formula from JSEP to convert b=AS to TIAS value.
+ bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95
+ - (50 * 40 * 8);
+ } else {
+ bandwidth = undefined;
+ }
+ encodingParameters.forEach(function(params) {
+ params.maxBitrate = bandwidth;
+ });
+ }
+ return encodingParameters;
+};
+
+// parses http://draft.ortc.org/#rtcrtcpparameters*
+SDPUtils.parseRtcpParameters = function(mediaSection) {
+ var rtcpParameters = {};
+
+ // Gets the first SSRC. Note tha with RTX there might be multiple
+ // SSRCs.
+ var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(obj) {
+ return obj.attribute === 'cname';
+ })[0];
+ if (remoteSsrc) {
+ rtcpParameters.cname = remoteSsrc.value;
+ rtcpParameters.ssrc = remoteSsrc.ssrc;
+ }
+
+ // Edge uses the compound attribute instead of reducedSize
+ // compound is !reducedSize
+ var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize');
+ rtcpParameters.reducedSize = rsize.length > 0;
+ rtcpParameters.compound = rsize.length === 0;
+
+ // parses the rtcp-mux attrŅbute.
+ // Note that Edge does not support unmuxed RTCP.
+ var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux');
+ rtcpParameters.mux = mux.length > 0;
+
+ return rtcpParameters;
+};
+
+// parses either a=msid: or a=ssrc:... msid lines and returns
+// the id of the MediaStream and MediaStreamTrack.
+SDPUtils.parseMsid = function(mediaSection) {
+ var parts;
+ var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:');
+ if (spec.length === 1) {
+ parts = spec[0].substr(7).split(' ');
+ return {stream: parts[0], track: parts[1]};
+ }
+ var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:')
+ .map(function(line) {
+ return SDPUtils.parseSsrcMedia(line);
+ })
+ .filter(function(msidParts) {
+ return msidParts.attribute === 'msid';
+ });
+ if (planB.length > 0) {
+ parts = planB[0].value.split(' ');
+ return {stream: parts[0], track: parts[1]};
+ }
+};
+
+// SCTP
+// parses draft-ietf-mmusic-sctp-sdp-26 first and falls back
+// to draft-ietf-mmusic-sctp-sdp-05
+SDPUtils.parseSctpDescription = function(mediaSection) {
+ var mline = SDPUtils.parseMLine(mediaSection);
+ var maxSizeLine = SDPUtils.matchPrefix(mediaSection, 'a=max-message-size:');
+ var maxMessageSize;
+ if (maxSizeLine.length > 0) {
+ maxMessageSize = parseInt(maxSizeLine[0].substr(19), 10);
+ }
+ if (isNaN(maxMessageSize)) {
+ maxMessageSize = 65536;
+ }
+ var sctpPort = SDPUtils.matchPrefix(mediaSection, 'a=sctp-port:');
+ if (sctpPort.length > 0) {
+ return {
+ port: parseInt(sctpPort[0].substr(12), 10),
+ protocol: mline.fmt,
+ maxMessageSize: maxMessageSize
+ };
+ }
+ var sctpMapLines = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:');
+ if (sctpMapLines.length > 0) {
+ var parts = SDPUtils.matchPrefix(mediaSection, 'a=sctpmap:')[0]
+ .substr(10)
+ .split(' ');
+ return {
+ port: parseInt(parts[0], 10),
+ protocol: parts[1],
+ maxMessageSize: maxMessageSize
+ };
+ }
+};
+
+// SCTP
+// outputs the draft-ietf-mmusic-sctp-sdp-26 version that all browsers
+// support by now receiving in this format, unless we originally parsed
+// as the draft-ietf-mmusic-sctp-sdp-05 format (indicated by the m-line
+// protocol of DTLS/SCTP -- without UDP/ or TCP/)
+SDPUtils.writeSctpDescription = function(media, sctp) {
+ var output = [];
+ if (media.protocol !== 'DTLS/SCTP') {
+ output = [
+ 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.protocol + '\r\n',
+ 'c=IN IP4 0.0.0.0\r\n',
+ 'a=sctp-port:' + sctp.port + '\r\n'
+ ];
+ } else {
+ output = [
+ 'm=' + media.kind + ' 9 ' + media.protocol + ' ' + sctp.port + '\r\n',
+ 'c=IN IP4 0.0.0.0\r\n',
+ 'a=sctpmap:' + sctp.port + ' ' + sctp.protocol + ' 65535\r\n'
+ ];
+ }
+ if (sctp.maxMessageSize !== undefined) {
+ output.push('a=max-message-size:' + sctp.maxMessageSize + '\r\n');
+ }
+ return output.join('');
+};
+
+// Generate a session ID for SDP.
+// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1
+// recommends using a cryptographically random +ve 64-bit value
+// but right now this should be acceptable and within the right range
+SDPUtils.generateSessionId = function() {
+ return Math.random().toString().substr(2, 21);
+};
+
+// Write boilder plate for start of SDP
+// sessId argument is optional - if not supplied it will
+// be generated randomly
+// sessVersion is optional and defaults to 2
+// sessUser is optional and defaults to 'thisisadapterortc'
+SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) {
+ var sessionId;
+ var version = sessVer !== undefined ? sessVer : 2;
+ if (sessId) {
+ sessionId = sessId;
+ } else {
+ sessionId = SDPUtils.generateSessionId();
+ }
+ var user = sessUser || 'thisisadapterortc';
+ // FIXME: sess-id should be an NTP timestamp.
+ return 'v=0\r\n' +
+ 'o=' + user + ' ' + sessionId + ' ' + version +
+ ' IN IP4 127.0.0.1\r\n' +
+ 's=-\r\n' +
+ 't=0 0\r\n';
+};
+
+SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) {
+ var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps);
+
+ // Map ICE parameters (ufrag, pwd) to SDP.
+ sdp += SDPUtils.writeIceParameters(
+ transceiver.iceGatherer.getLocalParameters());
+
+ // Map DTLS parameters to SDP.
+ sdp += SDPUtils.writeDtlsParameters(
+ transceiver.dtlsTransport.getLocalParameters(),
+ type === 'offer' ? 'actpass' : 'active');
+
+ sdp += 'a=mid:' + transceiver.mid + '\r\n';
+
+ if (transceiver.direction) {
+ sdp += 'a=' + transceiver.direction + '\r\n';
+ } else if (transceiver.rtpSender && transceiver.rtpReceiver) {
+ sdp += 'a=sendrecv\r\n';
+ } else if (transceiver.rtpSender) {
+ sdp += 'a=sendonly\r\n';
+ } else if (transceiver.rtpReceiver) {
+ sdp += 'a=recvonly\r\n';
+ } else {
+ sdp += 'a=inactive\r\n';
+ }
+
+ if (transceiver.rtpSender) {
+ // spec.
+ var msid = 'msid:' + stream.id + ' ' +
+ transceiver.rtpSender.track.id + '\r\n';
+ sdp += 'a=' + msid;
+
+ // for Chrome.
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
+ ' ' + msid;
+ if (transceiver.sendEncodingParameters[0].rtx) {
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
+ ' ' + msid;
+ sdp += 'a=ssrc-group:FID ' +
+ transceiver.sendEncodingParameters[0].ssrc + ' ' +
+ transceiver.sendEncodingParameters[0].rtx.ssrc +
+ '\r\n';
+ }
+ }
+ // FIXME: this should be written by writeRtpDescription.
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc +
+ ' cname:' + SDPUtils.localCName + '\r\n';
+ if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) {
+ sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc +
+ ' cname:' + SDPUtils.localCName + '\r\n';
+ }
+ return sdp;
+};
+
+// Gets the direction from the mediaSection or the sessionpart.
+SDPUtils.getDirection = function(mediaSection, sessionpart) {
+ // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv.
+ var lines = SDPUtils.splitLines(mediaSection);
+ for (var i = 0; i < lines.length; i++) {
+ switch (lines[i]) {
+ case 'a=sendrecv':
+ case 'a=sendonly':
+ case 'a=recvonly':
+ case 'a=inactive':
+ return lines[i].substr(2);
+ default:
+ // FIXME: What should happen here?
+ }
+ }
+ if (sessionpart) {
+ return SDPUtils.getDirection(sessionpart);
+ }
+ return 'sendrecv';
+};
+
+SDPUtils.getKind = function(mediaSection) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ var mline = lines[0].split(' ');
+ return mline[0].substr(2);
+};
+
+SDPUtils.isRejected = function(mediaSection) {
+ return mediaSection.split(' ', 2)[1] === '0';
+};
+
+SDPUtils.parseMLine = function(mediaSection) {
+ var lines = SDPUtils.splitLines(mediaSection);
+ var parts = lines[0].substr(2).split(' ');
+ return {
+ kind: parts[0],
+ port: parseInt(parts[1], 10),
+ protocol: parts[2],
+ fmt: parts.slice(3).join(' ')
+ };
+};
+
+SDPUtils.parseOLine = function(mediaSection) {
+ var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0];
+ var parts = line.substr(2).split(' ');
+ return {
+ username: parts[0],
+ sessionId: parts[1],
+ sessionVersion: parseInt(parts[2], 10),
+ netType: parts[3],
+ addressType: parts[4],
+ address: parts[5]
+ };
+};
+
+// a very naive interpretation of a valid SDP.
+SDPUtils.isValidSDP = function(blob) {
+ if (typeof blob !== 'string' || blob.length === 0) {
+ return false;
+ }
+ var lines = SDPUtils.splitLines(blob);
+ for (var i = 0; i < lines.length; i++) {
+ if (lines[i].length < 2 || lines[i].charAt(1) !== '=') {
+ return false;
+ }
+ // TODO: check the modifier a bit more.
+ }
+ return true;
+};
+
+// Expose public methods.
+if (typeof module === 'object') {
+ module.exports = SDPUtils;
+}