diff options
Diffstat (limited to 'testing/web-platform/tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html')
-rw-r--r-- | testing/web-platform/tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html b/testing/web-platform/tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html new file mode 100644 index 0000000000..f779f5a94c --- /dev/null +++ b/testing/web-platform/tests/webrtc/RTCRtpTransceiver-setCodecPreferences.html @@ -0,0 +1,322 @@ +<!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/H264'); + + assert_greater_than(lines.length, 1); + assert_true(lines[0].indexOf("H264") !== -1, "H264 should be the first codec"); + }, `setCodecPreferences() should allow setting H264 as first codec`); + + 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`); + + promise_test(async (t) => { + const pc = new RTCPeerConnection(); + t.add_cleanup(() => pc.close()); + const transceiver = pc.addTransceiver('video'); + const {codecs} = RTCRtpSender.getCapabilities('video'); + // Reorder codecs, swap H264 and VP8. + let vp8 = -1; + let h264 = -1; + let firstCodec; + let i; + for (i = 0; i < codecs.length; i++) { + const codec = codecs[i]; + if (codec.mimeType === 'video/VP8' && vp8 === -1) { + vp8 = i; + if (h264 !== -1) { + codecs[vp8] = codecs[h264]; + codecs[h264] = codec; + firstCodec = 'VP8'; + break; + } + } + if (codec.mimeType === 'video/H264' && h264 === -1) { + h264 = i; + if (vp8 !== -1) { + codecs[h264] = codecs[vp8]; + codecs[vp8] = codec; + firstCodec = 'H264'; + break; + } + } + } + assert_not_equals(firstCodec, undefined, 'VP8 and H264 codecs 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 video codecs in createOffer`); + + </script> |