| <!doctype html> |
| <meta charset=utf-8> |
| <title>RTCRtpParameters encodings</title> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="/webrtc/dictionary-helper.js"></script> |
| <script src="/webrtc/RTCRtpParameters-helper.js"></script> |
| <script src="/webrtc/third_party/sdp/sdp.js"></script> |
| <script> |
| 'use strict'; |
| |
| async function negotiate(pc1, pc2) { |
| await pc1.setLocalDescription(); |
| await pc2.setRemoteDescription(pc1.localDescription); |
| await pc2.setLocalDescription(); |
| await pc1.setRemoteDescription(pc2.localDescription); |
| } |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('video'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| let capability = capabilities.find((capability) => { |
| return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid" && |
| capability.direction != "stopped"; |
| }); |
| assert_not_equals(capability, undefined); |
| }, `the video transceiver.getHeaderExtensionsToNegotiate() includes mandatory extensions`); |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('audio'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| let capability = capabilities.find((capability) => { |
| return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid" && |
| capability.direction != "stopped"; |
| }); |
| assert_not_equals(capability, undefined); |
| }, `the audio transceiver.getHeaderExtensionsToNegotiate() includes mandatory extensions`); |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('audio'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| capabilities[0].uri = ""; |
| assert_throws_js(TypeError, () => { |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| }, 'transceiver should throw TypeError when setting an empty URI'); |
| }, `setHeaderExtensionsToNegotiate throws TypeError on encountering missing URI`); |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('audio'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| capabilities[0].uri = "4711"; |
| assert_throws_dom("NotSupportedError", () => { |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| }, 'transceiver should throw NotSupported when setting an unknown URI'); |
| }, `setHeaderExtensionsToNegotiate throws NotSupported on encountering unknown URI`); |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('audio'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| let capability = capabilities.find((capability) => { |
| return capability.uri == "urn:ietf:params:rtp-hdrext:sdes:mid"; |
| }); |
| ["sendonly", "recvonly", "inactive", "stopped"].map(direction => { |
| capability.direction = direction; |
| assert_throws_dom("InvalidModificationError", () => { |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| }, `transceiver should throw InvalidModificationError when setting a mandatory header extension\'s direction to ${direction}`); |
| }); |
| }, `setHeaderExtensionsToNegotiate throws InvalidModificationError when setting a mandatory header extension\'s direction to something else than "sendrecv"`); |
| |
| test(function(t) { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('audio'); |
| let capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| let selected_capability = capabilities.find((capability) => { |
| return capability.direction == "sendrecv" && |
| capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid"; |
| }); |
| selected_capability.direction = "stopped"; |
| const offered_capabilities = transceiver.getHeaderExtensionsToNegotiate; |
| let altered_capability = capabilities.find((capability) => { |
| return capability.uri == selected_capability.uri && |
| capability.direction == "stopped"; |
| }); |
| assert_not_equals(altered_capability, undefined); |
| }, `modified direction set by setHeaderExtensionsToNegotiate is visible in headerExtensionsOffered`); |
| |
| promise_test(async t => { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('video'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| const offer = await pc.createOffer(); |
| const extmaps = offer |
| .sdp |
| .split("\n") |
| .filter(line => { return line.includes("a=extmap:"); }) |
| .join("\n"); |
| for (const capability of capabilities) { |
| if (capability.direction == "stopped") { |
| assert_false(extmaps.includes(capability.uri)); |
| } else { |
| assert_true(extmaps.includes(capability.uri)); |
| } |
| } |
| }, `unstopped extensions turn up in offer`); |
| |
| promise_test(async t => { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| const transceiver = pc.addTransceiver('video'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| const selected_capability = capabilities.find((capability) => { |
| return capability.direction == "sendrecv" && |
| capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid"; |
| }); |
| selected_capability.direction = "stopped"; |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| const offer = await pc.createOffer(); |
| const extmaps = offer |
| .sdp |
| .split("\n") |
| .filter(line => { return line.includes("a=extmap:"); }) |
| .join("\n"); |
| for (const capability of capabilities) { |
| if (capability.direction == "stopped") { |
| assert_false(extmaps.includes(capability.uri)); |
| } else { |
| assert_true(extmaps.includes(capability.uri)); |
| } |
| } |
| }, `stopped extensions do not turn up in offers`); |
| |
| promise_test(async t => { |
| const pc1 = new RTCPeerConnection(); |
| t.add_cleanup(() => pc1.close()); |
| const pc2 = new RTCPeerConnection(); |
| t.add_cleanup(() => pc2.close()); |
| |
| // Disable a non-mandatory extension before first negotiation. |
| const transceiver = pc1.addTransceiver('video'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| const selected_capability = capabilities.find((capability) => { |
| return capability.direction == "sendrecv" && |
| capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid"; |
| }); |
| selected_capability.direction = "stopped"; |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| |
| await negotiate(pc1, pc2); |
| const negotiated_capabilites = transceiver.getNegotiatedHeaderExtensions(); |
| |
| // Attempt enabling the extension. |
| selected_capability.direction = "sendrecv"; |
| |
| // The enabled extension should not be part of the negotiated set. |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| await negotiate(pc1, pc2); |
| assert_not_equals( |
| transceiver.getNegotiatedHeaderExtensions().find(capability => { |
| return capability.uri == selected_capability.uri && |
| capability.direction == "sendrecv"; |
| }), undefined); |
| }, `the set of negotiated extensions grows with subsequent offers`); |
| |
| promise_test(async t => { |
| const pc1 = new RTCPeerConnection(); |
| t.add_cleanup(() => pc1.close()); |
| const pc2 = new RTCPeerConnection(); |
| t.add_cleanup(() => pc2.close()); |
| |
| // Disable a non-mandatory extension before first negotiation. |
| const transceiver = pc1.addTransceiver('video'); |
| const capabilities = transceiver.getHeaderExtensionsToNegotiate(); |
| const selected_capability = capabilities.find((capability) => { |
| return capability.direction == "sendrecv" && |
| capability.uri != "urn:ietf:params:rtp-hdrext:sdes:mid"; |
| }); |
| selected_capability.direction = "stopped"; |
| transceiver.setHeaderExtensionsToNegotiate(capabilities); |
| |
| await negotiate(pc1, pc2); |
| const negotiated_capabilites = transceiver.getNegotiatedHeaderExtensions(); |
| |
| for (const capability of negotiated_capabilites) { |
| assert_not_equals(capabilities.find((cap) => { |
| return cap.uri == capability.uri && cap.direction != "stopped"; |
| }), undefined); |
| } |
| for (const capability of capabilities) { |
| if (capability.direction != "stopped") { |
| assert_not_equals(negotiated_capabilites.find((cap) => { |
| return cap.uri == capability.uri; |
| }), undefined); |
| } |
| } |
| }, `the set of negotiated extensions is the set of unstopped extensions`); |
| |
| promise_test(async t => { |
| const pc = new RTCPeerConnection(); |
| t.add_cleanup(() => pc.close()); |
| |
| const t1 = pc.addTransceiver('video'); |
| const t2 = pc.addTransceiver('video'); |
| const extensionUri = 'urn:3gpp:video-orientation'; |
| |
| assert_true(!!t1.getHeaderExtensionsToNegotiate().find(ext => ext.uri === extensionUri)); |
| const ext1 = t1.getHeaderExtensionsToNegotiate(); |
| ext1.find(ext => ext.uri === extensionUri).direction = 'stopped'; |
| t1.setHeaderExtensionsToNegotiate(ext1); |
| |
| assert_true(!!t2.getHeaderExtensionsToNegotiate().find(ext => ext.uri === extensionUri)); |
| const ext2 = t2.getHeaderExtensionsToNegotiate(); |
| ext2.find(ext => ext.uri === extensionUri).direction = 'sendrecv'; |
| t2.setHeaderExtensionsToNegotiate(ext2); |
| |
| const offer = await pc.createOffer(); |
| const sections = SDPUtils.splitSections(offer.sdp); |
| sections.shift(); |
| const extensions = sections.map(section => { |
| return SDPUtils.matchPrefix(section, 'a=extmap:') |
| .map(SDPUtils.parseExtmap); |
| }); |
| assert_equals(extensions.length, 2); |
| assert_false(!!extensions[0].find(extension => extension.uri === extensionUri)); |
| assert_true(!!extensions[1].find(extension => extension.uri === extensionUri)); |
| }, 'Extensions can be deactivated on a per-mline basis'); |
| |
| </script> |