[tv][webrtc]fix DF241113-00425 timeout issue 87/320687/1
authorchen <chen89.chen@samsung.com>
Thu, 21 Nov 2024 18:29:56 +0000 (02:29 +0800)
committerchen <chen89.chen@samsung.com>
Thu, 21 Nov 2024 18:30:08 +0000 (02:30 +0800)
Change-Id: Ifd86e799580a883097a536b4e6d4d1e043947514
Signed-off-by: chen <chen89.chen@samsung.com>
335 files changed:
common/tct-webrtc-w3c-tests/tests.full.xml
common/tct-webrtc-w3c-tests/tests.xml
common/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCError.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/RollbackEvents.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/coverage/RTCDTMFSender.txt [deleted file]
common/tct-webrtc-w3c-tests/webrtc/coverage/identity.txt [deleted file]
common/tct-webrtc-w3c-tests/webrtc/coverage/set-session-description.txt [deleted file]
common/tct-webrtc-w3c-tests/webrtc/getstats.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/historical.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/legacy/README.txt [deleted file]
common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/media/test-v-128k-320x240-24fps-8kfr.webm [deleted file]
common/tct-webrtc-w3c-tests/webrtc/no-media-call.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/promises-call.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-setup.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/handover.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/sdes-dont-dont-dont.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/resources/RTCCertificate-postMessage-iframe.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simplecall.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/simulcast.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCConfiguration-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCDTMFSender-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCDataChannel-binaryType.window.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-perfect-negotiation-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpCapabilities-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpParameters-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/RTCStats-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/dictionary-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/get-host-info.sub.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/idlharness.https.window.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/support/permission-helper.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/third_party/README.md [deleted file]
common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/LICENSE [deleted file]
common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/index.html [deleted file]
common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/sdp.js [deleted file]
common/tct-webrtc-w3c-tests/webrtc/w3c/COPYING [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/RollbackEvents.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/RTCDTMFSender.txt [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/identity.txt [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/set-session-description.txt [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/historical.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/README.txt [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/media/test-v-128k-320x240-24fps-8kfr.webm [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-setup.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sdes-dont-dont-dont.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/resources/RTCCertificate-postMessage-iframe.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/simulcast.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCConfiguration-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDTMFSender-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDataChannel-binaryType.window.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-perfect-negotiation-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpCapabilities-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpParameters-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCStats-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/dictionary-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/get-host-info.sub.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/idlharness.https.window.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/support/permission-helper.js [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/README.md [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/LICENSE [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/index.html [new file with mode: 0755]
common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/sdp.js [new file with mode: 0755]

index 5b4049b3d2c17ee55d94b1eb79e5175cff396159..b955385165e01c6626dd25312afca269990a7529 100755 (executable)
@@ -8,7 +8,7 @@
       </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>
@@ -20,7 +20,7 @@
       </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>
@@ -32,7 +32,7 @@
       </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>
@@ -44,7 +44,7 @@
       </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>
@@ -56,7 +56,7 @@
       </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>
@@ -68,7 +68,7 @@
       </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>
@@ -80,7 +80,7 @@
       </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>
@@ -92,7 +92,7 @@
       </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>
index 21cc23baab586e9a0f5f986182e5584707a9315c..309a9e0f91b7ac018a9096af9c12fb77ea281f21 100755 (executable)
       </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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=33</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="new RTCPeerConnection(config) - with &quot;&quot; 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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=34</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setConfiguration(config) - with &quot;&quot; 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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=35</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="new RTCPeerConnection(config) - with [&quot;stun:stun1.example.net&quot;, &quot;&quot;] 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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=36</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setConfiguration(config) - with [&quot;stun:stun1.example.net&quot;, &quot;&quot;] 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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addIceCandidate({&quot;candidate&quot;:&quot;&quot;,&quot;sdpMid&quot;:null,&quot;sdpMLineIndex&quot;: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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;value=2</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createDataChannel with label &quot;foo&quot; 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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;value=12</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createDataChannel with protocol &quot;foo&quot; 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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=45</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=46</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=47</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;value=1</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach &quot;new&quot; when starting in &quot;complete&quot;" 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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;value=2</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach &quot;new&quot; when starting in &quot;gathering&quot;" 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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to &quot;checking&quot; and then &quot;complete&quot;" 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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;value=6</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="renegotiation that closes all transports should result in ICE gathering state &quot;new&quot;" 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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=45</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=46</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=47</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=48</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=49</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=50</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=51</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=52</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=53</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=54</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=55</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=56</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=57</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=58</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=59</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=60</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=61</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=62</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=63</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=64</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=65</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=66</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=67</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=68</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=69</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=70</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=71</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=1</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addTrack: &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=15</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setRemoteDescription(offer): &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=22</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addTransceiver(track): &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createOffer() with offerToReceiveAudio should create a &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=5</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=6</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped &quot;sendrecv&quot; 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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=7</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio set to false with a track should create a &quot;sendonly&quot; 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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=8</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio set to false with a &quot;recvonly&quot; transceiver should change the direction to &quot;inactive&quot;" 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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=9</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="subsequent offerToReceiveAudio set to false with a track should change the direction to &quot;sendonly&quot;" 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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=11</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createOffer() with offerToReceiveVideo should create a &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=12</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=13</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped &quot;sendrecv&quot; 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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=14</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo set to false with a track should create a &quot;sendonly&quot; 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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=15</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo set to false with a &quot;recvonly&quot; transceiver should change the direction to &quot;inactive&quot;" 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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=16</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="Rsubsequent offerToReceiveVideo set to false with a track should change the direction to &quot;sendonly&quot;" 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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=17</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio and Video should create two &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=33</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="new RTCPeerConnection(config) - with &quot;&quot; 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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=34</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setConfiguration(config) - with &quot;&quot; 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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=35</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="new RTCPeerConnection(config) - with [&quot;stun:stun1.example.net&quot;, &quot;&quot;] 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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;value=36</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setConfiguration(config) - with [&quot;stun:stun1.example.net&quot;, &quot;&quot;] 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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html?total_num=41&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html?total_num=20&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html?total_num=15&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html?total_num=23&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html?total_num=4&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addIceCandidate({&quot;candidate&quot;:&quot;&quot;,&quot;sdpMid&quot;:null,&quot;sdpMLineIndex&quot;: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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html?total_num=22&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;value=2</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createDataChannel with label &quot;foo&quot; 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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;value=12</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createDataChannel with protocol &quot;foo&quot; 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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=45</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=46</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=47</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html?total_num=47&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;value=1</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach &quot;new&quot; when starting in &quot;complete&quot;" 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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;value=2</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(rollback) of original offer should cause iceGatheringState to reach &quot;new&quot; when starting in &quot;gathering&quot;" 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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setLocalDescription(reoffer) with a new transport should cause iceGatheringState to go to &quot;checking&quot; and then &quot;complete&quot;" 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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;value=6</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="renegotiation that closes all transports should result in ICE gathering state &quot;new&quot;" 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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=45</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=46</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=47</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=48</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=49</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=50</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=51</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=52</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=53</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=54</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=55</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=56</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=57</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=58</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=59</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=60</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=61</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=62</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=63</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=64</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=65</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=66</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=67</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=68</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=69</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=70</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=71</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html?total_num=71&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html?total_num=16&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html?total_num=14&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html?total_num=25&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html?total_num=9&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html?total_num=21&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html?total_num=12&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html?total_num=13&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=1</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addTrack: &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=15</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="setRemoteDescription(offer): &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;value=22</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="addTransceiver(track): &quot;transceiver == {sender,receiver}&quot;" 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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=43</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=44</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html?total_num=44&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=32</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=33</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=34</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=35</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=36</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=37</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=38</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=39</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=40</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=41</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=42</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html?total_num=42&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html?total_num=17&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html?total_num=10&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=19</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=20</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=21</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=22</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=23</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=24</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=25</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=26</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=27</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=28</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=29</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=30</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=31</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html?total_num=31&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html?total_num=5&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/historical.html?total_num=8&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=4</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createOffer() with offerToReceiveAudio should create a &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=5</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=6</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio option should be ignored if a non-stopped &quot;sendrecv&quot; 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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=7</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio set to false with a track should create a &quot;sendonly&quot; 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&amp;locator_key=id&amp;value=8</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=8</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio set to false with a &quot;recvonly&quot; transceiver should change the direction to &quot;inactive&quot;" 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&amp;locator_key=id&amp;value=9</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=9</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="subsequent offerToReceiveAudio set to false with a track should change the direction to &quot;sendonly&quot;" 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&amp;locator_key=id&amp;value=10</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=11</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=11</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="createOffer() with offerToReceiveVideo should create a &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=12</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=12</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=13</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=13</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo option should be ignored if a non-stopped &quot;sendrecv&quot; 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&amp;locator_key=id&amp;value=14</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=14</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo set to false with a track should create a &quot;sendonly&quot; 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&amp;locator_key=id&amp;value=15</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=15</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveVideo set to false with a &quot;recvonly&quot; transceiver should change the direction to &quot;inactive&quot;" 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&amp;locator_key=id&amp;value=16</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=16</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="Rsubsequent offerToReceiveVideo set to false with a track should change the direction to &quot;sendonly&quot;" 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&amp;locator_key=id&amp;value=17</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;value=17</test_script_entry>
         </description>
       </testcase>
       <testcase purpose="offerToReceiveAudio and Video should create two &quot;recvonly&quot; 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&amp;locator_key=id&amp;value=18</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html?total_num=18&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=7</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html?total_num=7&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=5</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=6</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html?total_num=6&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=4</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html?total_num=4&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html?total_num=2&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=1</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=2</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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&amp;locator_key=id&amp;value=3</test_script_entry>
+          <test_script_entry>/opt/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html?total_num=3&amp;locator_key=id&amp;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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html b/common/tct-webrtc-w3c-tests/webrtc/RTCCertificate-postMessage.html
deleted file mode 100755 (executable)
index 1f6fe8a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html b/common/tct-webrtc-w3c-tests/webrtc/RTCCertificate.html
deleted file mode 100755 (executable)
index df1ff7d..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html b/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-bundlePolicy.html
deleted file mode 100755 (executable)
index 352d66d..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html b/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceCandidatePoolSize.html
deleted file mode 100755 (executable)
index 6a7c9eb..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html b/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceServers.html
deleted file mode 100755 (executable)
index cad3f9a..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html b/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-iceTransportPolicy.html
deleted file mode 100755 (executable)
index fc336d3..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html b/common/tct-webrtc-w3c-tests/webrtc/RTCConfiguration-rtcpMuxPolicy.html
deleted file mode 100755 (executable)
index 129bff7..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-insertDTMF.https.html
deleted file mode 100755 (executable)
index f63a1c1..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange-long.https.html
deleted file mode 100755 (executable)
index 46cfe8d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDTMFSender-ontonechange.https.html
deleted file mode 100755 (executable)
index f1fc74d..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-bufferedAmount.html
deleted file mode 100755 (executable)
index 65840a6..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-close.html
deleted file mode 100755 (executable)
index 7da8a52..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-iceRestart.html
deleted file mode 100755 (executable)
index 1475bc4..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-id.html
deleted file mode 100755 (executable)
index 39e33eb..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannel-send.html
deleted file mode 100755 (executable)
index 03e14ea..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDataChannelEvent-constructor.html
deleted file mode 100755 (executable)
index 96b5d20..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-getRemoteCertificates.html
deleted file mode 100755 (executable)
index a2530dd..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html b/common/tct-webrtc-w3c-tests/webrtc/RTCDtlsTransport-state.html
deleted file mode 100755 (executable)
index ce4b77a..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCError.html b/common/tct-webrtc-w3c-tests/webrtc/RTCError.html
deleted file mode 100755 (executable)
index e9cda41..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCIceCandidate-constructor.html
deleted file mode 100755 (executable)
index 2249347..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCIceConnectionState-candidate-pair.https.html
deleted file mode 100755 (executable)
index 9590794..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html b/common/tct-webrtc-w3c-tests/webrtc/RTCIceTransport.html
deleted file mode 100755 (executable)
index c281e91..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-SLD-SRD-timing.https.html
deleted file mode 100755 (executable)
index 6ed0613..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-add-track-no-deadlock.https.html
deleted file mode 100755 (executable)
index 9e7e819..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-connectionSetup.html
deleted file mode 100755 (executable)
index 904df3a..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate-timing.https.html
deleted file mode 100755 (executable)
index cd74e47..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addIceCandidate.html
deleted file mode 100755 (executable)
index 0535ccc..0000000
+++ /dev/null
@@ -1,473 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTrack.https.html
deleted file mode 100755 (executable)
index e65874b..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-addTransceiver.https.html
deleted file mode 100755 (executable)
index 50ab553..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-canTrickleIceCandidates.html
deleted file mode 100755 (executable)
index df7789a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-candidate-in-sdp.https.html
deleted file mode 100755 (executable)
index 8f12e6a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-connectionState.https.html
deleted file mode 100755 (executable)
index 148b61c..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-constructor.html
deleted file mode 100755 (executable)
index 3c0ab23..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createAnswer.html
deleted file mode 100755 (executable)
index c16e95f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createDataChannel.html
deleted file mode 100755 (executable)
index b5f03ac..0000000
+++ /dev/null
@@ -1,700 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-createOffer.html
deleted file mode 100755 (executable)
index 3c78e34..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-description-attributes-timing.https.html
deleted file mode 100755 (executable)
index 3e2e6e7..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-explicit-rollback-iceGatheringState.html
deleted file mode 100755 (executable)
index a1ceed8..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-generateCertificate.html
deleted file mode 100755 (executable)
index 752df84..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getStats.https.html
deleted file mode 100755 (executable)
index c989960..0000000
+++ /dev/null
@@ -1,264 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-getTransceivers.html
deleted file mode 100755 (executable)
index d114a59..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-helper-test.html
deleted file mode 100755 (executable)
index ad213e2..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState-disconnected.https.html
deleted file mode 100755 (executable)
index ce86556..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceConnectionState.https.html
deleted file mode 100755 (executable)
index e6980bb..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-iceGatheringState.html
deleted file mode 100755 (executable)
index 19eea15..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-mandatory-getStats.https.html
deleted file mode 100755 (executable)
index 514782d..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ondatachannel.html
deleted file mode 100755 (executable)
index f491d6c..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onicecandidateerror.https.html
deleted file mode 100755 (executable)
index 03d54c8..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onnegotiationneeded.html
deleted file mode 100755 (executable)
index 6b8313a..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-onsignalingstatechanged.https.html
deleted file mode 100755 (executable)
index 7808aac..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-ontrack.https.html
deleted file mode 100755 (executable)
index ebf2417..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-operations.https.html
deleted file mode 100755 (executable)
index cc2a921..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-removeTrack.https.html
deleted file mode 100755 (executable)
index fbb5451..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce-onnegotiationneeded.https.html
deleted file mode 100755 (executable)
index 88fbda8..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-restartIce.https.html
deleted file mode 100755 (executable)
index 4ec2c63..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setDescription-transceiver.html
deleted file mode 100755 (executable)
index fac9d47..0000000
+++ /dev/null
@@ -1,295 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-answer.html
deleted file mode 100755 (executable)
index 5928f6a..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-offer.html
deleted file mode 100755 (executable)
index 10f194e..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-parameterless.https.html
deleted file mode 100755 (executable)
index e4a4a63..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-pranswer.html
deleted file mode 100755 (executable)
index 9fd5101..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription-rollback.html
deleted file mode 100755 (executable)
index 4a6a427..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setLocalDescription.html
deleted file mode 100755 (executable)
index 8ad07eb..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-answer.html
deleted file mode 100755 (executable)
index 0265d44..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-nomsid.html
deleted file mode 100755 (executable)
index 8fed355..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-offer.html
deleted file mode 100755 (executable)
index f4e7ccd..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-pranswer.html
deleted file mode 100755 (executable)
index 98f6eae..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html
deleted file mode 100755 (executable)
index 2894cbb..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-rollback.html
deleted file mode 100755 (executable)
index 60f21b5..0000000
+++ /dev/null
@@ -1,595 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html
deleted file mode 100755 (executable)
index 3876523..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-setRemoteDescription.html
deleted file mode 100755 (executable)
index 37164b8..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-track-stats.https.html
deleted file mode 100755 (executable)
index 4375922..0000000
+++ /dev/null
@@ -1,490 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-transceivers.https.html
deleted file mode 100755 (executable)
index 22f8780..0000000
+++ /dev/null
@@ -1,508 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnection-videoDetectorTest.html
deleted file mode 100755 (executable)
index b35866b..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceErrorEvent.html
deleted file mode 100755 (executable)
index 3dfa61d..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCPeerConnectionIceEvent-constructor.html
deleted file mode 100755 (executable)
index b97e36f..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-codecs.html
deleted file mode 100755 (executable)
index 5edc4d8..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-encodings.html
deleted file mode 100755 (executable)
index fe38af8..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-headerExtensions.html
deleted file mode 100755 (executable)
index 655a3bd..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-rtcp.html
deleted file mode 100755 (executable)
index 4c42d7e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpParameters-transactionId.html
deleted file mode 100755 (executable)
index fc515f5..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getCapabilities.html
deleted file mode 100755 (executable)
index cdc3801..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getContributingSources.https.html
deleted file mode 100755 (executable)
index ec386c1..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpReceiver-getParameters.html
deleted file mode 100755 (executable)
index 9e5f9a6..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-encode-same-track-twice.https.html
deleted file mode 100755 (executable)
index 2366fb9..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-getCapabilities.html
deleted file mode 100755 (executable)
index 320da7c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-replaceTrack.https.html
deleted file mode 100755 (executable)
index c7e737c..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setParameters.html
deleted file mode 100755 (executable)
index 61519ce..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-setStreams.https.html
deleted file mode 100755 (executable)
index 0f6ddee..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender-transport.https.html
deleted file mode 100755 (executable)
index 81bf694..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpSender.https.html
deleted file mode 100755 (executable)
index d0e0526..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-direction.html
deleted file mode 100755 (executable)
index 6eedd23..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html
deleted file mode 100755 (executable)
index 945cf53..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stop.html
deleted file mode 100755 (executable)
index 62b9510..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver-stopping.https.html
deleted file mode 100755 (executable)
index 3a66118..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html b/common/tct-webrtc-w3c-tests/webrtc/RTCRtpTransceiver.https.html
deleted file mode 100755 (executable)
index 076c805..0000000
+++ /dev/null
@@ -1,2316 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-constructor.html
deleted file mode 100755 (executable)
index 818d0e0..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html b/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-events.html
deleted file mode 100755 (executable)
index 93bb78b..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html b/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxChannels.html
deleted file mode 100755 (executable)
index 79751ce..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html b/common/tct-webrtc-w3c-tests/webrtc/RTCSctpTransport-maxMessageSize.html
deleted file mode 100755 (executable)
index 6d87ca0..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-constructor.html
deleted file mode 100755 (executable)
index 5a33718..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html b/common/tct-webrtc-w3c-tests/webrtc/RTCTrackEvent-fire.html
deleted file mode 100755 (executable)
index 4c0ef63..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/RollbackEvents.https.html b/common/tct-webrtc-w3c-tests/webrtc/RollbackEvents.https.html
deleted file mode 100755 (executable)
index 98e5f40..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/coverage/RTCDTMFSender.txt b/common/tct-webrtc-w3c-tests/webrtc/coverage/RTCDTMFSender.txt
deleted file mode 100755 (executable)
index aa30021..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/coverage/identity.txt b/common/tct-webrtc-w3c-tests/webrtc/coverage/identity.txt
deleted file mode 100755 (executable)
index 0d1bcca..0000000
+++ /dev/null
@@ -1,220 +0,0 @@
-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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/coverage/set-session-description.txt b/common/tct-webrtc-w3c-tests/webrtc/coverage/set-session-description.txt
deleted file mode 100755 (executable)
index f2bb422..0000000
+++ /dev/null
@@ -1,240 +0,0 @@
-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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/getstats.html b/common/tct-webrtc-w3c-tests/webrtc/getstats.html
deleted file mode 100755 (executable)
index 2a9c53c..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/historical.html b/common/tct-webrtc-w3c-tests/webrtc/historical.html
deleted file mode 100755 (executable)
index 9fa4948..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/legacy/README.txt b/common/tct-webrtc-w3c-tests/webrtc/legacy/README.txt
deleted file mode 100755 (executable)
index 8adbf6a..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-This directory contains files that test for behavior relevant to webrtc,
-particularly defined in https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
diff --git a/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html b/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-addStream.https.html
deleted file mode 100755 (executable)
index cc2935a..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html b/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCPeerConnection-createOffer-offerToReceive.html
deleted file mode 100755 (executable)
index a767d68..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html b/common/tct-webrtc-w3c-tests/webrtc/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html
deleted file mode 100755 (executable)
index 96c7083..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html b/common/tct-webrtc-w3c-tests/webrtc/legacy/onaddstream.https.html
deleted file mode 100755 (executable)
index ea70884..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/media/test-v-128k-320x240-24fps-8kfr.webm b/common/tct-webrtc-w3c-tests/webrtc/media/test-v-128k-320x240-24fps-8kfr.webm
deleted file mode 100755 (executable)
index 189c472..0000000
Binary files a/common/tct-webrtc-w3c-tests/webrtc/media/test-v-128k-320x240-24fps-8kfr.webm and /dev/null differ
diff --git a/common/tct-webrtc-w3c-tests/webrtc/no-media-call.html b/common/tct-webrtc-w3c-tests/webrtc/no-media-call.html
deleted file mode 100755 (executable)
index ea8938e..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/promises-call.html b/common/tct-webrtc-w3c-tests/webrtc/promises-call.html
deleted file mode 100755 (executable)
index 9ba91c7..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/RTCPeerConnection-payloadTypes.html
deleted file mode 100755 (executable)
index d370415..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/bundle.https.html
deleted file mode 100755 (executable)
index d41b03c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/candidate-exchange.https.html
deleted file mode 100755 (executable)
index a351ed1..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/crypto-suite.https.html
deleted file mode 100755 (executable)
index 5dc9a2a..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-fingerprint-validation.html
deleted file mode 100755 (executable)
index 05ab237..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-setup.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/dtls-setup.https.html
deleted file mode 100755 (executable)
index cadea10..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/handover-datachannel.html
deleted file mode 100755 (executable)
index 2e3e18a..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/handover.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/handover.html
deleted file mode 100755 (executable)
index 0f36779..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/ice-state.https.html
deleted file mode 100755 (executable)
index a0c8c2b..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/ice-ufragpwd.html
deleted file mode 100755 (executable)
index dc48f82..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/jsep-initial-offer.https.html
deleted file mode 100755 (executable)
index 675ed35..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/missing-fields.html
deleted file mode 100755 (executable)
index d632bb8..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/msid-parse.html
deleted file mode 100755 (executable)
index c4b28fb..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-clockrate.html
deleted file mode 100755 (executable)
index 03ab37c..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-demuxing.html
deleted file mode 100755 (executable)
index 879e8dd..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/rtp-payloadtypes.html
deleted file mode 100755 (executable)
index 96e1f69..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/rtx-codecs.https.html
deleted file mode 100755 (executable)
index 0bb2963..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/sctp-format.html
deleted file mode 100755 (executable)
index 6b6067f..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/sdes-dont-dont-dont.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/sdes-dont-dont-dont.html
deleted file mode 100755 (executable)
index c89f209..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-answer.html
deleted file mode 100755 (executable)
index 946c26f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/simulcast-offer.html
deleted file mode 100755 (executable)
index 0465da2..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/split.https.html
deleted file mode 100755 (executable)
index f979f44..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/unknown-mediatypes.html
deleted file mode 100755 (executable)
index cf8d6ff..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html b/common/tct-webrtc-w3c-tests/webrtc/protocol/video-codecs.https.html
deleted file mode 100755 (executable)
index 8014a53..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html b/common/tct-webrtc-w3c-tests/webrtc/receiver-track-live.https.html
deleted file mode 100755 (executable)
index b0b01a4..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html b/common/tct-webrtc-w3c-tests/webrtc/recvonly-transceiver-can-become-sendrecv.https.html
deleted file mode 100755 (executable)
index 9227223..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/resources/RTCCertificate-postMessage-iframe.html b/common/tct-webrtc-w3c-tests/webrtc/resources/RTCCertificate-postMessage-iframe.html
deleted file mode 100755 (executable)
index 9e52ba0..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html b/common/tct-webrtc-w3c-tests/webrtc/simplecall-no-ssrcs.https.html
deleted file mode 100755 (executable)
index 0e45354..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simplecall.https.html b/common/tct-webrtc-w3c-tests/webrtc/simplecall.https.html
deleted file mode 100755 (executable)
index 4b246ec..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html b/common/tct-webrtc-w3c-tests/webrtc/simulcast/basic.https.html
deleted file mode 100755 (executable)
index 4b1d9ec..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/simulcast/getStats.https.html
deleted file mode 100755 (executable)
index f3abe48..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html b/common/tct-webrtc-w3c-tests/webrtc/simulcast/h264.https.html
deleted file mode 100755 (executable)
index c8e6980..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html b/common/tct-webrtc-w3c-tests/webrtc/simulcast/setParameters-active.https.html
deleted file mode 100755 (executable)
index cf5bc07..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/simulcast.js b/common/tct-webrtc-w3c-tests/webrtc/simulcast/simulcast.js
deleted file mode 100755 (executable)
index 3811d3a..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-'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);
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html b/common/tct-webrtc-w3c-tests/webrtc/simulcast/vp8.https.html
deleted file mode 100755 (executable)
index 8f4db09..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCConfiguration-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCConfiguration-helper.js
deleted file mode 100755 (executable)
index fb8eb50..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-'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}`);
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCDTMFSender-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCDTMFSender-helper.js
deleted file mode 100755 (executable)
index 4316c38..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-'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];
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCDataChannel-binaryType.window.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCDataChannel-binaryType.window.js
deleted file mode 100755 (executable)
index c63281b..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-'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`);
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-helper.js
deleted file mode 100755 (executable)
index ac43527..0000000
+++ /dev/null
@@ -1,715 +0,0 @@
-'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!');
-      });
-};
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-perfect-negotiation-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCPeerConnection-perfect-negotiation-helper.js
deleted file mode 100755 (executable)
index ed647bb..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-'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`);
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpCapabilities-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpCapabilities-helper.js
deleted file mode 100755 (executable)
index fb297c3..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-'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');
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpParameters-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCRtpParameters-helper.js
deleted file mode 100755 (executable)
index d7653c3..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-'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');
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/RTCStats-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/RTCStats-helper.js
deleted file mode 100755 (executable)
index 33cbf4a..0000000
+++ /dev/null
@@ -1,1073 +0,0 @@
-'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');
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/dictionary-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/dictionary-helper.js
deleted file mode 100755 (executable)
index dab7e49..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-'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);
-  }
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/get-host-info.sub.js b/common/tct-webrtc-w3c-tests/webrtc/support/get-host-info.sub.js
deleted file mode 100755 (executable)
index fd32553..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/**
- * 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';
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/idlharness.https.window.js b/common/tct-webrtc-w3c-tests/webrtc/support/idlharness.https.window.js
deleted file mode 100755 (executable)
index 98685f1..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-// 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();
-  }
-);
diff --git a/common/tct-webrtc-w3c-tests/webrtc/support/permission-helper.js b/common/tct-webrtc-w3c-tests/webrtc/support/permission-helper.js
deleted file mode 100755 (executable)
index 769f3ee..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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");
-    }
-  }
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/third_party/README.md b/common/tct-webrtc-w3c-tests/webrtc/third_party/README.md
deleted file mode 100755 (executable)
index 56a2295..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-## 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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/LICENSE b/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/LICENSE
deleted file mode 100755 (executable)
index 09502ec..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-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.
diff --git a/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/index.html b/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/index.html
deleted file mode 100755 (executable)
index 474d421..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/sdp.js b/common/tct-webrtc-w3c-tests/webrtc/third_party/sdp/sdp.js
deleted file mode 100755 (executable)
index d2a2870..0000000
+++ /dev/null
@@ -1,825 +0,0 @@
-/* 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;
-}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/COPYING b/common/tct-webrtc-w3c-tests/webrtc/w3c/COPYING
new file mode 100755 (executable)
index 0000000..34e18be
--- /dev/null
@@ -0,0 +1,11 @@
+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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate-postMessage.html
new file mode 100755 (executable)
index 0000000..9a9c236
--- /dev/null
@@ -0,0 +1,62 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCCertificate.html
new file mode 100755 (executable)
index 0000000..cfdb655
--- /dev/null
@@ -0,0 +1,264 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-bundlePolicy.html
new file mode 100755 (executable)
index 0000000..a189d06
--- /dev/null
@@ -0,0 +1,128 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceCandidatePoolSize.html
new file mode 100755 (executable)
index 0000000..29352ad
--- /dev/null
@@ -0,0 +1,117 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceServers.html
new file mode 100755 (executable)
index 0000000..2cb3418
--- /dev/null
@@ -0,0 +1,215 @@
+<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-iceTransportPolicy.html
new file mode 100755 (executable)
index 0000000..e25579b
--- /dev/null
@@ -0,0 +1,105 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCConfiguration-rtcpMuxPolicy.html
new file mode 100755 (executable)
index 0000000..497d025
--- /dev/null
@@ -0,0 +1,196 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-insertDTMF.https.html
new file mode 100755 (executable)
index 0000000..cd3a513
--- /dev/null
@@ -0,0 +1,176 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange-long.https.html
new file mode 100755 (executable)
index 0000000..ced351a
--- /dev/null
@@ -0,0 +1,50 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDTMFSender-ontonechange.https.html
new file mode 100755 (executable)
index 0000000..45f3ddb
--- /dev/null
@@ -0,0 +1,285 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-bufferedAmount.html
new file mode 100755 (executable)
index 0000000..16656bb
--- /dev/null
@@ -0,0 +1,207 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-close.html
new file mode 100755 (executable)
index 0000000..7434cb5
--- /dev/null
@@ -0,0 +1,180 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-iceRestart.html
new file mode 100755 (executable)
index 0000000..b42c860
--- /dev/null
@@ -0,0 +1,76 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-id.html
new file mode 100755 (executable)
index 0000000..9257fdd
--- /dev/null
@@ -0,0 +1,345 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannel-send.html
new file mode 100755 (executable)
index 0000000..e9b4d4d
--- /dev/null
@@ -0,0 +1,206 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDataChannelEvent-constructor.html
new file mode 100755 (executable)
index 0000000..df4fd43
--- /dev/null
@@ -0,0 +1,41 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-getRemoteCertificates.html
new file mode 100755 (executable)
index 0000000..893797e
--- /dev/null
@@ -0,0 +1,97 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCDtlsTransport-state.html
new file mode 100755 (executable)
index 0000000..daa706e
--- /dev/null
@@ -0,0 +1,89 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCError.html
new file mode 100755 (executable)
index 0000000..9a1c23e
--- /dev/null
@@ -0,0 +1,89 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceCandidate-constructor.html
new file mode 100755 (executable)
index 0000000..a1e3953
--- /dev/null
@@ -0,0 +1,234 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceConnectionState-candidate-pair.https.html
new file mode 100755 (executable)
index 0000000..d00793f
--- /dev/null
@@ -0,0 +1,33 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCIceTransport.html
new file mode 100755 (executable)
index 0000000..32ee022
--- /dev/null
@@ -0,0 +1,146 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-SLD-SRD-timing.https.html
new file mode 100755 (executable)
index 0000000..6391fea
--- /dev/null
@@ -0,0 +1,24 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-add-track-no-deadlock.https.html
new file mode 100755 (executable)
index 0000000..b75596d
--- /dev/null
@@ -0,0 +1,31 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-connectionSetup.html
new file mode 100755 (executable)
index 0000000..de1e63c
--- /dev/null
@@ -0,0 +1,92 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate-timing.https.html
new file mode 100755 (executable)
index 0000000..f8de261
--- /dev/null
@@ -0,0 +1,149 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addIceCandidate.html
new file mode 100755 (executable)
index 0000000..a8f8081
--- /dev/null
@@ -0,0 +1,473 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTrack.https.html
new file mode 100755 (executable)
index 0000000..9543fda
--- /dev/null
@@ -0,0 +1,394 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-addTransceiver.https.html
new file mode 100755 (executable)
index 0000000..9846f72
--- /dev/null
@@ -0,0 +1,441 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-canTrickleIceCandidates.html
new file mode 100755 (executable)
index 0000000..a08e980
--- /dev/null
@@ -0,0 +1,62 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-candidate-in-sdp.https.html
new file mode 100755 (executable)
index 0000000..69736c3
--- /dev/null
@@ -0,0 +1,26 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-connectionState.https.html
new file mode 100755 (executable)
index 0000000..bd34063
--- /dev/null
@@ -0,0 +1,291 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-constructor.html
new file mode 100755 (executable)
index 0000000..f6d421b
--- /dev/null
@@ -0,0 +1,76 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createAnswer.html
new file mode 100755 (executable)
index 0000000..717054a
--- /dev/null
@@ -0,0 +1,28 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createDataChannel.html
new file mode 100755 (executable)
index 0000000..6e9057e
--- /dev/null
@@ -0,0 +1,700 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-createOffer.html
new file mode 100755 (executable)
index 0000000..3e11613
--- /dev/null
@@ -0,0 +1,100 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-description-attributes-timing.https.html
new file mode 100755 (executable)
index 0000000..8dee8e4
--- /dev/null
@@ -0,0 +1,81 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-explicit-rollback-iceGatheringState.html
new file mode 100755 (executable)
index 0000000..9122ffc
--- /dev/null
@@ -0,0 +1,53 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-generateCertificate.html
new file mode 100755 (executable)
index 0000000..7b861ed
--- /dev/null
@@ -0,0 +1,120 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getStats.https.html
new file mode 100755 (executable)
index 0000000..42cb94e
--- /dev/null
@@ -0,0 +1,264 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-getTransceivers.html
new file mode 100755 (executable)
index 0000000..288ad0e
--- /dev/null
@@ -0,0 +1,39 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-helper-test.html
new file mode 100755 (executable)
index 0000000..e87d9e5
--- /dev/null
@@ -0,0 +1,21 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState-disconnected.https.html
new file mode 100755 (executable)
index 0000000..08cd50d
--- /dev/null
@@ -0,0 +1,30 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceConnectionState.https.html
new file mode 100755 (executable)
index 0000000..ffef5c6
--- /dev/null
@@ -0,0 +1,396 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-iceGatheringState.html
new file mode 100755 (executable)
index 0000000..a2cb54a
--- /dev/null
@@ -0,0 +1,244 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-mandatory-getStats.https.html
new file mode 100755 (executable)
index 0000000..10c1855
--- /dev/null
@@ -0,0 +1,260 @@
+<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ondatachannel.html
new file mode 100755 (executable)
index 0000000..4b70a7e
--- /dev/null
@@ -0,0 +1,374 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onicecandidateerror.https.html
new file mode 100755 (executable)
index 0000000..54b1bda
--- /dev/null
@@ -0,0 +1,38 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onnegotiationneeded.html
new file mode 100755 (executable)
index 0000000..3bbd226
--- /dev/null
@@ -0,0 +1,461 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-onsignalingstatechanged.https.html
new file mode 100755 (executable)
index 0000000..4bc99ea
--- /dev/null
@@ -0,0 +1,71 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-ontrack.https.html
new file mode 100755 (executable)
index 0000000..5f40ba5
--- /dev/null
@@ -0,0 +1,258 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-operations.https.html
new file mode 100755 (executable)
index 0000000..b780e2d
--- /dev/null
@@ -0,0 +1,133 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-removeTrack.https.html
new file mode 100755 (executable)
index 0000000..8dce89b
--- /dev/null
@@ -0,0 +1,338 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce-onnegotiationneeded.https.html
new file mode 100755 (executable)
index 0000000..5f5849a
--- /dev/null
@@ -0,0 +1,29 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-restartIce.https.html
new file mode 100755 (executable)
index 0000000..17c1710
--- /dev/null
@@ -0,0 +1,421 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setDescription-transceiver.html
new file mode 100755 (executable)
index 0000000..f7cf106
--- /dev/null
@@ -0,0 +1,295 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-answer.html
new file mode 100755 (executable)
index 0000000..a7ef5a1
--- /dev/null
@@ -0,0 +1,205 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-offer.html
new file mode 100755 (executable)
index 0000000..e3984e8
--- /dev/null
@@ -0,0 +1,212 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-parameterless.https.html
new file mode 100755 (executable)
index 0000000..8c14abd
--- /dev/null
@@ -0,0 +1,131 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-pranswer.html
new file mode 100755 (executable)
index 0000000..b8d4bfe
--- /dev/null
@@ -0,0 +1,156 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription-rollback.html
new file mode 100755 (executable)
index 0000000..2c6d355
--- /dev/null
@@ -0,0 +1,159 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setLocalDescription.html
new file mode 100755 (executable)
index 0000000..18b452f
--- /dev/null
@@ -0,0 +1,152 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-answer.html
new file mode 100755 (executable)
index 0000000..d2a4a4c
--- /dev/null
@@ -0,0 +1,123 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-nomsid.html
new file mode 100755 (executable)
index 0000000..8d9c6f3
--- /dev/null
@@ -0,0 +1,40 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-offer.html
new file mode 100755 (executable)
index 0000000..12f7ba7
--- /dev/null
@@ -0,0 +1,239 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-pranswer.html
new file mode 100755 (executable)
index 0000000..25db663
--- /dev/null
@@ -0,0 +1,166 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-replaceTrack.https.html
new file mode 100755 (executable)
index 0000000..9721872
--- /dev/null
@@ -0,0 +1,115 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-rollback.html
new file mode 100755 (executable)
index 0000000..14559ec
--- /dev/null
@@ -0,0 +1,595 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription-tracks.https.html
new file mode 100755 (executable)
index 0000000..2e74afc
--- /dev/null
@@ -0,0 +1,316 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-setRemoteDescription.html
new file mode 100755 (executable)
index 0000000..719a08e
--- /dev/null
@@ -0,0 +1,158 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-track-stats.https.html
new file mode 100755 (executable)
index 0000000..a7d81a6
--- /dev/null
@@ -0,0 +1,490 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-transceivers.https.html
new file mode 100755 (executable)
index 0000000..f6fa003
--- /dev/null
@@ -0,0 +1,508 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnection-videoDetectorTest.html
new file mode 100755 (executable)
index 0000000..af0b124
--- /dev/null
@@ -0,0 +1,87 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceErrorEvent.html
new file mode 100755 (executable)
index 0000000..84e76fc
--- /dev/null
@@ -0,0 +1,26 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCPeerConnectionIceEvent-constructor.html
new file mode 100755 (executable)
index 0000000..3bd632f
--- /dev/null
@@ -0,0 +1,85 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-codecs.html
new file mode 100755 (executable)
index 0000000..4badcd7
--- /dev/null
@@ -0,0 +1,206 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-encodings.html
new file mode 100755 (executable)
index 0000000..29f18a3
--- /dev/null
@@ -0,0 +1,517 @@
+<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-headerExtensions.html
new file mode 100755 (executable)
index 0000000..6731a7b
--- /dev/null
@@ -0,0 +1,74 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-rtcp.html
new file mode 100755 (executable)
index 0000000..40619ed
--- /dev/null
@@ -0,0 +1,104 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpParameters-transactionId.html
new file mode 100755 (executable)
index 0000000..d1a0544
--- /dev/null
@@ -0,0 +1,151 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getCapabilities.html
new file mode 100755 (executable)
index 0000000..f94e599
--- /dev/null
@@ -0,0 +1,39 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getContributingSources.https.html
new file mode 100755 (executable)
index 0000000..62aaaa4
--- /dev/null
@@ -0,0 +1,35 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpReceiver-getParameters.html
new file mode 100755 (executable)
index 0000000..3ea890c
--- /dev/null
@@ -0,0 +1,58 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-encode-same-track-twice.https.html
new file mode 100755 (executable)
index 0000000..e7c8f5f
--- /dev/null
@@ -0,0 +1,66 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-getCapabilities.html
new file mode 100755 (executable)
index 0000000..1b40c91
--- /dev/null
@@ -0,0 +1,45 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-replaceTrack.https.html
new file mode 100755 (executable)
index 0000000..946002e
--- /dev/null
@@ -0,0 +1,270 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setParameters.html
new file mode 100755 (executable)
index 0000000..0910c4c
--- /dev/null
@@ -0,0 +1,30 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-setStreams.https.html
new file mode 100755 (executable)
index 0000000..7157719
--- /dev/null
@@ -0,0 +1,128 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender-transport.https.html
new file mode 100755 (executable)
index 0000000..98c3106
--- /dev/null
@@ -0,0 +1,152 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpSender.https.html
new file mode 100755 (executable)
index 0000000..13442b1
--- /dev/null
@@ -0,0 +1,20 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-direction.html
new file mode 100755 (executable)
index 0000000..8263572
--- /dev/null
@@ -0,0 +1,94 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-setCodecPreferences.html
new file mode 100755 (executable)
index 0000000..d2cfe41
--- /dev/null
@@ -0,0 +1,275 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stop.html
new file mode 100755 (executable)
index 0000000..1eee4a9
--- /dev/null
@@ -0,0 +1,138 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver-stopping.https.html
new file mode 100755 (executable)
index 0000000..cc3a678
--- /dev/null
@@ -0,0 +1,108 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCRtpTransceiver.https.html
new file mode 100755 (executable)
index 0000000..3ec5ae7
--- /dev/null
@@ -0,0 +1,2316 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-constructor.html
new file mode 100755 (executable)
index 0000000..591bf2c
--- /dev/null
@@ -0,0 +1,125 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-events.html
new file mode 100755 (executable)
index 0000000..177b0e6
--- /dev/null
@@ -0,0 +1,55 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxChannels.html
new file mode 100755 (executable)
index 0000000..813164a
--- /dev/null
@@ -0,0 +1,49 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCSctpTransport-maxMessageSize.html
new file mode 100755 (executable)
index 0000000..8974dd6
--- /dev/null
@@ -0,0 +1,206 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-constructor.html
new file mode 100755 (executable)
index 0000000..e8d1fc7
--- /dev/null
@@ -0,0 +1,159 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RTCTrackEvent-fire.html
new file mode 100755 (executable)
index 0000000..9c5f43d
--- /dev/null
@@ -0,0 +1,152 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/RollbackEvents.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/RollbackEvents.https.html
new file mode 100755 (executable)
index 0000000..a333f74
--- /dev/null
@@ -0,0 +1,231 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/RTCDTMFSender.txt b/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/RTCDTMFSender.txt
new file mode 100755 (executable)
index 0000000..aa30021
--- /dev/null
@@ -0,0 +1,122 @@
+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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/identity.txt b/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/identity.txt
new file mode 100755 (executable)
index 0000000..0d1bcca
--- /dev/null
@@ -0,0 +1,220 @@
+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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/set-session-description.txt b/common/tct-webrtc-w3c-tests/webrtc/w3c/coverage/set-session-description.txt
new file mode 100755 (executable)
index 0000000..f2bb422
--- /dev/null
@@ -0,0 +1,240 @@
+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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/getstats.html
new file mode 100755 (executable)
index 0000000..578a6b6
--- /dev/null
@@ -0,0 +1,130 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/historical.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/historical.html
new file mode 100755 (executable)
index 0000000..79238f5
--- /dev/null
@@ -0,0 +1,51 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/README.txt b/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/README.txt
new file mode 100755 (executable)
index 0000000..8adbf6a
--- /dev/null
@@ -0,0 +1,2 @@
+This directory contains files that test for behavior relevant to webrtc,
+particularly defined in https://w3c.github.io/webrtc-pc/#legacy-interface-extensions
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-addStream.https.html
new file mode 100755 (executable)
index 0000000..ee13cdf
--- /dev/null
@@ -0,0 +1,74 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCPeerConnection-createOffer-offerToReceive.html
new file mode 100755 (executable)
index 0000000..7e6dcbc
--- /dev/null
@@ -0,0 +1,274 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/RTCRtpTransceiver-with-OfferToReceive-options.https.html
new file mode 100755 (executable)
index 0000000..4932140
--- /dev/null
@@ -0,0 +1,172 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/legacy/onaddstream.https.html
new file mode 100755 (executable)
index 0000000..e36119e
--- /dev/null
@@ -0,0 +1,157 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/media/test-v-128k-320x240-24fps-8kfr.webm b/common/tct-webrtc-w3c-tests/webrtc/w3c/media/test-v-128k-320x240-24fps-8kfr.webm
new file mode 100755 (executable)
index 0000000..189c472
Binary files /dev/null and b/common/tct-webrtc-w3c-tests/webrtc/w3c/media/test-v-128k-320x240-24fps-8kfr.webm differ
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/no-media-call.html
new file mode 100755 (executable)
index 0000000..77563a1
--- /dev/null
@@ -0,0 +1,100 @@
+<!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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/promises-call.html
new file mode 100755 (executable)
index 0000000..66f7e65
--- /dev/null
@@ -0,0 +1,113 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/RTCPeerConnection-payloadTypes.html
new file mode 100755 (executable)
index 0000000..8857c27
--- /dev/null
@@ -0,0 +1,49 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/bundle.https.html
new file mode 100755 (executable)
index 0000000..fdcc356
--- /dev/null
@@ -0,0 +1,95 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/candidate-exchange.https.html
new file mode 100755 (executable)
index 0000000..5a69cf0
--- /dev/null
@@ -0,0 +1,218 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/crypto-suite.https.html
new file mode 100755 (executable)
index 0000000..8ed2529
--- /dev/null
@@ -0,0 +1,85 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-fingerprint-validation.html
new file mode 100755 (executable)
index 0000000..59fdfc9
--- /dev/null
@@ -0,0 +1,37 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-setup.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/dtls-setup.https.html
new file mode 100755 (executable)
index 0000000..0043265
--- /dev/null
@@ -0,0 +1,86 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover-datachannel.html
new file mode 100755 (executable)
index 0000000..6313496
--- /dev/null
@@ -0,0 +1,62 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/handover.html
new file mode 100755 (executable)
index 0000000..89e98f2
--- /dev/null
@@ -0,0 +1,72 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-state.https.html
new file mode 100755 (executable)
index 0000000..f12f3a3
--- /dev/null
@@ -0,0 +1,130 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/ice-ufragpwd.html
new file mode 100755 (executable)
index 0000000..2ad7629
--- /dev/null
@@ -0,0 +1,55 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/jsep-initial-offer.https.html
new file mode 100755 (executable)
index 0000000..5c1cb8a
--- /dev/null
@@ -0,0 +1,41 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/missing-fields.html
new file mode 100755 (executable)
index 0000000..4d178a7
--- /dev/null
@@ -0,0 +1,47 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/msid-parse.html
new file mode 100755 (executable)
index 0000000..be40319
--- /dev/null
@@ -0,0 +1,71 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-clockrate.html
new file mode 100755 (executable)
index 0000000..28909d8
--- /dev/null
@@ -0,0 +1,42 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-demuxing.html
new file mode 100755 (executable)
index 0000000..fc14ed2
--- /dev/null
@@ -0,0 +1,58 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtp-payloadtypes.html
new file mode 100755 (executable)
index 0000000..a7d2a25
--- /dev/null
@@ -0,0 +1,50 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/rtx-codecs.https.html
new file mode 100755 (executable)
index 0000000..2e26f07
--- /dev/null
@@ -0,0 +1,115 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sctp-format.html
new file mode 100755 (executable)
index 0000000..747b7b3
--- /dev/null
@@ -0,0 +1,25 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sdes-dont-dont-dont.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/sdes-dont-dont-dont.html
new file mode 100755 (executable)
index 0000000..2932c8e
--- /dev/null
@@ -0,0 +1,57 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-answer.html
new file mode 100755 (executable)
index 0000000..26104a3
--- /dev/null
@@ -0,0 +1,62 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/simulcast-offer.html
new file mode 100755 (executable)
index 0000000..bb8c33a
--- /dev/null
@@ -0,0 +1,33 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/split.https.html
new file mode 100755 (executable)
index 0000000..32fdd29
--- /dev/null
@@ -0,0 +1,98 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/unknown-mediatypes.html
new file mode 100755 (executable)
index 0000000..0bf497f
--- /dev/null
@@ -0,0 +1,34 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/protocol/video-codecs.https.html
new file mode 100755 (executable)
index 0000000..3425c9f
--- /dev/null
@@ -0,0 +1,95 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/receiver-track-live.https.html
new file mode 100755 (executable)
index 0000000..31251e8
--- /dev/null
@@ -0,0 +1,72 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/recvonly-transceiver-can-become-sendrecv.https.html
new file mode 100755 (executable)
index 0000000..508c145
--- /dev/null
@@ -0,0 +1,50 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/resources/RTCCertificate-postMessage-iframe.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/resources/RTCCertificate-postMessage-iframe.html
new file mode 100755 (executable)
index 0000000..9e52ba0
--- /dev/null
@@ -0,0 +1,9 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall-no-ssrcs.https.html
new file mode 100755 (executable)
index 0000000..8807403
--- /dev/null
@@ -0,0 +1,118 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simplecall.https.html
new file mode 100755 (executable)
index 0000000..7d9387a
--- /dev/null
@@ -0,0 +1,109 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/basic.https.html
new file mode 100755 (executable)
index 0000000..f109543
--- /dev/null
@@ -0,0 +1,23 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/getStats.https.html
new file mode 100755 (executable)
index 0000000..2c0d2a6
--- /dev/null
@@ -0,0 +1,34 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/h264.https.html
new file mode 100755 (executable)
index 0000000..a9e19e4
--- /dev/null
@@ -0,0 +1,31 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/setParameters-active.https.html
new file mode 100755 (executable)
index 0000000..a34f7bc
--- /dev/null
@@ -0,0 +1,54 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/simulcast.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/simulcast.js
new file mode 100755 (executable)
index 0000000..3811d3a
--- /dev/null
@@ -0,0 +1,131 @@
+'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);
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/simulcast/vp8.https.html
new file mode 100755 (executable)
index 0000000..624ce26
--- /dev/null
@@ -0,0 +1,26 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCConfiguration-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCConfiguration-helper.js
new file mode 100755 (executable)
index 0000000..fb8eb50
--- /dev/null
@@ -0,0 +1,24 @@
+'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}`);
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDTMFSender-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDTMFSender-helper.js
new file mode 100755 (executable)
index 0000000..4316c38
--- /dev/null
@@ -0,0 +1,149 @@
+'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];
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDataChannel-binaryType.window.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCDataChannel-binaryType.window.js
new file mode 100755 (executable)
index 0000000..c63281b
--- /dev/null
@@ -0,0 +1,27 @@
+'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`);
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-helper.js
new file mode 100755 (executable)
index 0000000..ac43527
--- /dev/null
@@ -0,0 +1,715 @@
+'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!');
+      });
+};
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-perfect-negotiation-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCPeerConnection-perfect-negotiation-helper.js
new file mode 100755 (executable)
index 0000000..ed647bb
--- /dev/null
@@ -0,0 +1,153 @@
+'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`);
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpCapabilities-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpCapabilities-helper.js
new file mode 100755 (executable)
index 0000000..fb297c3
--- /dev/null
@@ -0,0 +1,52 @@
+'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');
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpParameters-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCRtpParameters-helper.js
new file mode 100755 (executable)
index 0000000..d7653c3
--- /dev/null
@@ -0,0 +1,269 @@
+'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');
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCStats-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/RTCStats-helper.js
new file mode 100755 (executable)
index 0000000..33cbf4a
--- /dev/null
@@ -0,0 +1,1073 @@
+'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');
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/dictionary-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/dictionary-helper.js
new file mode 100755 (executable)
index 0000000..dab7e49
--- /dev/null
@@ -0,0 +1,101 @@
+'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);
+  }
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/get-host-info.sub.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/get-host-info.sub.js
new file mode 100755 (executable)
index 0000000..fd32553
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * 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';
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/idlharness.https.window.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/idlharness.https.window.js
new file mode 100755 (executable)
index 0000000..98685f1
--- /dev/null
@@ -0,0 +1,146 @@
+// 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();
+  }
+);
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/support/permission-helper.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/support/permission-helper.js
new file mode 100755 (executable)
index 0000000..769f3ee
--- /dev/null
@@ -0,0 +1,24 @@
+// 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");
+    }
+  }
+}
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/README.md b/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/README.md
new file mode 100755 (executable)
index 0000000..56a2295
--- /dev/null
@@ -0,0 +1,5 @@
+## 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
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/LICENSE b/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/LICENSE
new file mode 100755 (executable)
index 0000000..09502ec
--- /dev/null
@@ -0,0 +1,19 @@
+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.
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/index.html b/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/index.html
new file mode 100755 (executable)
index 0000000..474d421
--- /dev/null
@@ -0,0 +1,9 @@
+<!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>
diff --git a/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/sdp.js b/common/tct-webrtc-w3c-tests/webrtc/w3c/third_party/sdp/sdp.js
new file mode 100755 (executable)
index 0000000..d2a2870
--- /dev/null
@@ -0,0 +1,825 @@
+/* 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;
+}