mirror of
https://github.com/servo/servo.git
synced 2025-10-08 20:49:24 +01:00
322 lines
12 KiB
HTML
322 lines
12 KiB
HTML
<!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>
|