summaryrefslogtreecommitdiffstats
path: root/dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html')
-rw-r--r--dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html325
1 files changed, 325 insertions, 0 deletions
diff --git a/dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html b/dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html
new file mode 100644
index 0000000000..78c6bb986c
--- /dev/null
+++ b/dom/media/webrtc/tests/mochitests/test_peerConnection_extmapRenegotiation.html
@@ -0,0 +1,325 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <script type="application/javascript" src="pc.js"></script>
+ <script type="application/javascript" src="iceTestUtils.js"></script>
+</head>
+<body>
+<pre id="test">
+<script type="application/javascript">
+ createHTML({
+ bug: "1799932",
+ title: "RTCPeerConnection check renegotiation of extmap"
+ });
+
+ function setExtmap(sdp, uri, id) {
+ const regex = new RegExp(`a=extmap:[0-9]+(\/[a-z]+)? ${uri}`, 'g');
+ if (id) {
+ return sdp.replaceAll(regex, `a=extmap:${id}$1 ${uri}`);
+ } else {
+ return sdp.replaceAll(regex, `a=unknownattr`);
+ }
+ }
+
+ function getExtmap(sdp, uri) {
+ const regex = new RegExp(`a=extmap:([0-9]+)(\/[a-z]+)? ${uri}`);
+ return sdp.match(regex)[1];
+ }
+
+ function replaceExtUri(sdp, oldUri, newUri) {
+ const regex = new RegExp(`(a=extmap:[0-9]+\/[a-z]+)? ${oldUri}`, 'g');
+ return sdp.replaceAll(regex, `$1 ${newUri}`);
+ }
+
+ const tests = [
+ async function checkAudioMidChange() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", 14);
+ info(`New reoffer: ${reoffer.sdp}`);
+ await pc2.setRemoteDescription(reoffer);
+ await pc2.setLocalDescription();
+ await wait(2000);
+ },
+
+ async function checkVideoMidChange() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", 14);
+ info(`New reoffer: ${reoffer.sdp}`);
+ await pc2.setRemoteDescription(reoffer);
+ await pc2.setLocalDescription();
+ await wait(2000);
+ },
+
+ async function checkAudioMidSwap() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ const midId = getExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid");
+ const ssrcLevelId = getExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", ssrcLevelId);
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", midId);
+ info(`New reoffer: ${reoffer.sdp}`);
+ try {
+ await pc2.setRemoteDescription(reoffer);
+ ok(false, "sRD should fail when it attempts extension id remapping");
+ } catch (e) {
+ ok(true, "sRD should fail when it attempts extension id remapping");
+ }
+ },
+
+ async function checkVideoMidSwap() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ const midId = getExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid");
+ const toffsetId = getExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:toffset");
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", toffsetId);
+ reoffer.sdp = setExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:toffset", midId);
+ info(`New reoffer: ${reoffer.sdp}`);
+ try {
+ await pc2.setRemoteDescription(reoffer);
+ ok(false, "sRD should fail when it attempts extension id remapping");
+ } catch (e) {
+ ok(true, "sRD should fail when it attempts extension id remapping");
+ }
+ },
+
+ async function checkAudioIdReuse() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ // Change uri, but not the id, so the id now refers to foo.
+ reoffer.sdp = replaceExtUri(reoffer.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", "foo");
+ info(`New reoffer: ${reoffer.sdp}`);
+ try {
+ await pc2.setRemoteDescription(reoffer);
+ ok(false, "sRD should fail when it attempts extension id remapping");
+ } catch (e) {
+ ok(true, "sRD should fail when it attempts extension id remapping");
+ }
+ },
+
+ async function checkVideoIdReuse() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({video: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ // Sadly, there's no way to tell the offerer to change the extmap. Other
+ // types of endpoint could conceivably do this, so we at least don't want
+ // to crash.
+ // TODO: Would be nice to be able to test this with an endpoint that
+ // actually changes the ids it uses.
+ const reoffer = await pc1.createOffer();
+ // Change uri, but not the id, so the id now refers to foo.
+ reoffer.sdp = replaceExtUri(reoffer.sdp, "urn:ietf:params:rtp-hdrext:toffset", "foo");
+ info(`New reoffer: ${reoffer.sdp}`);
+ try {
+ await pc2.setRemoteDescription(reoffer);
+ ok(false, "sRD should fail when it attempts extension id remapping");
+ } catch (e) {
+ ok(true, "sRD should fail when it attempts extension id remapping");
+ }
+ },
+
+ // What happens when remote answer uses an extmap id, and then a remote
+ // reoffer tries to use the same id for something else?
+ async function checkAudioIdReuseOffererThenAnswerer() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ await connect(pc1, pc2, 32000, "Initial connection");
+
+ const reoffer = await pc2.createOffer();
+ // Change uri, but not the id, so the id now refers to foo.
+ reoffer.sdp = replaceExtUri(reoffer.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", "foo");
+ info(`New reoffer: ${reoffer.sdp}`);
+ try {
+ await pc1.setRemoteDescription(reoffer);
+ ok(false, "sRD should fail when it attempts extension id remapping");
+ } catch (e) {
+ ok(true, "sRD should fail when it attempts extension id remapping");
+ }
+ },
+
+ // What happens when a remote offer uses a different extmap id than the
+ // default? Does the answerer remember the new id in reoffers?
+ async function checkAudioIdReuseOffererThenAnswerer() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ // Negotiate, but change id for ssrc-audio-level to something pc2 would
+ // not typically use.
+ await pc1.setLocalDescription();
+ const mungedOffer = setExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", 12);
+ await pc2.setRemoteDescription({sdp: mungedOffer, type: "offer"});
+ await pc2.setLocalDescription();
+
+ const reoffer = await pc2.createOffer();
+ is(getExtmap(reoffer.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level"), "12");
+ },
+
+ async function checkAudioUnnegotiatedIdReuse1() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ // Negotiate, but remove ssrc-audio-level from answer
+ await pc1.setLocalDescription();
+ const levelId = getExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ await pc2.setRemoteDescription(pc1.localDescription);
+ await pc2.setLocalDescription();
+ const answerNoExt = setExtmap(pc2.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", undefined);
+ await pc1.setRemoteDescription({sdp: answerNoExt, type: "answer"});
+
+ // Renegotiate, and use the id that offerer used for ssrc-audio-level for
+ // something different (while making sure we don't use it twice)
+ await pc2.setLocalDescription();
+ const mungedReoffer = setExtmap(pc2.localDescription.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", levelId);
+ const twiceMungedReoffer = setExtmap(mungedReoffer, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", undefined);
+ await pc1.setRemoteDescription({sdp: twiceMungedReoffer, type: "offer"});
+ },
+
+ async function checkAudioUnnegotiatedIdReuse2() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ // Negotiate, but remove ssrc-audio-level from offer. pc2 has never seen
+ // |levelId| in extmap yet, but internally probably wants to use that for
+ // ssrc-audio-level
+ await pc1.setLocalDescription();
+ const levelId = getExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ const offerNoExt = setExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", undefined);
+ await pc2.setRemoteDescription({sdp: offerNoExt, type: "offer"});
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // Renegotiate, but use |levelId| for something other than
+ // ssrc-audio-level. pc2 should not throw.
+ await pc1.setLocalDescription();
+ const mungedReoffer = setExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", levelId);
+ const twiceMungedReoffer = setExtmap(mungedReoffer, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", undefined);
+ await pc2.setRemoteDescription({sdp: twiceMungedReoffer, type: "offer"});
+ },
+
+ async function checkAudioUnnegotiatedIdReuse3() {
+ const pc1 = new RTCPeerConnection();
+ const pc2 = new RTCPeerConnection();
+
+ const stream = await navigator.mediaDevices.getUserMedia({audio: true});
+ pc1.addTrack(stream.getTracks()[0]);
+ pc2.addTrack(stream.getTracks()[0]);
+
+ // Negotiate, but replace ssrc-audio-level with something pc2 won't
+ // support in offer.
+ await pc1.setLocalDescription();
+ const levelId = getExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level");
+ const mungedOffer = replaceExtUri(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", "fooba");
+ await pc2.setRemoteDescription({sdp: mungedOffer, type: "offer"});
+ await pc2.setLocalDescription();
+ await pc1.setRemoteDescription(pc2.localDescription);
+
+ // Renegotiate, and use levelId for something pc2 _will_ support.
+ await pc1.setLocalDescription();
+ const mungedReoffer = setExtmap(pc1.localDescription.sdp, "urn:ietf:params:rtp-hdrext:sdes:mid", levelId);
+ const twiceMungedReoffer = setExtmap(mungedReoffer, "urn:ietf:params:rtp-hdrext:ssrc-audio-level", undefined);
+ await pc2.setRemoteDescription({sdp: twiceMungedReoffer, type: "offer"});
+ },
+
+ ];
+
+ runNetworkTest(async () => {
+ for (const test of tests) {
+ info(`Running test: ${test.name}`);
+ await test();
+ info(`Done running test: ${test.name}`);
+ }
+ });
+
+</script>
+</pre>
+</body>
+</html>