572 lines
21 KiB
HTML
572 lines
21 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<meta name="timeout" content="long">
|
|
<title>RTCRtpParameters codecs</title>
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
<script src="dictionary-helper.js"></script>
|
|
<script src="RTCRtpParameters-helper.js"></script>
|
|
<script src="RTCPeerConnection-helper.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
|
|
|
|
// 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];
|
|
}
|
|
|
|
function compareCodecParam(observed, expected) {
|
|
assert_equals(observed.payloadType, expected.payloadType);
|
|
assert_equals(observed.clockRate, expected.clockRate);
|
|
assert_equals(observed.channels, expected.channels);
|
|
// Comparisons of mime-type are case-insensitive (see
|
|
// https://datatracker.ietf.org/doc/html/rfc2045#section-5.1)
|
|
assert_equals(observed.mimeType.toLowerCase(), expected.mimeType.toLowerCase());
|
|
// This is not ideal; Firefox does not store fmtp verbatim, it stores a
|
|
// reserialiaztion of the parsed form. We would like to be able to test
|
|
// the other fields without tripping over that. So, we only test
|
|
// sdpFmtpLine if it is a property of |expected|.
|
|
if (expected.hasOwnProperty('sdpFmtpLine')) {
|
|
assert_equals(observed.sdpFmtpLine, expected.sdpFmtpLine);
|
|
}
|
|
}
|
|
|
|
function compareCodecParams(observed, expected) {
|
|
assert_equals(observed.length, expected.length);
|
|
for (let i = 0; i < observed.length; ++i) {
|
|
compareCodecParam(observed[i], expected[i]);
|
|
}
|
|
}
|
|
|
|
// Does not support disregarding unsupported codecs in the SDP, so is not
|
|
// suitable for all test-cases.
|
|
function checkCodecsAgainstSDP(codecs, msection) {
|
|
const rtpParameters = SDPUtils.parseRtpParameters(msection);
|
|
const {kind} = SDPUtils.parseMLine(msection);
|
|
|
|
assert_not_equals(codecs.length, 0);
|
|
assert_equals(codecs.length, rtpParameters.codecs.length);
|
|
for (let i = 0; i < codecs.length; ++i) {
|
|
const observed = codecs[i];
|
|
const fromSdp = rtpParameters.codecs[i];
|
|
const expected = {
|
|
payloadType: fromSdp.payloadType,
|
|
clockRate: fromSdp.clockRate,
|
|
mimeType: `${kind}/${fromSdp.name}`,
|
|
};
|
|
if (kind == 'audio') {
|
|
expected.channels = fromSdp.channels;
|
|
}
|
|
const fmtps = SDPUtils.matchPrefixAndTrim(msection, `a=fmtp:${fromSdp.payloadType}`);
|
|
if (fmtps.length == 1) {
|
|
expected.sdpFmtpLine = fmtps[0];
|
|
} else {
|
|
// compareCodecParam will check if observed.sdpFmtpLine is undefined if we
|
|
// set this, but will not perform any checks if we do not.
|
|
expected.sdpFmtpLine = undefined;
|
|
}
|
|
compareCodecParam(observed, expected);
|
|
}
|
|
}
|
|
|
|
['audio', 'video'].forEach(kind => {
|
|
/*
|
|
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(kind);
|
|
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 (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
const param = sender.getParameters();
|
|
validateSenderRtpParameters(param);
|
|
|
|
const codec = getFirstCodec(param);
|
|
|
|
if(codec.mimeType === undefined) {
|
|
codec.mimeType = `${kind}/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 (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
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 (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
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 (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
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 (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
const param = sender.getParameters();
|
|
validateSenderRtpParameters(param);
|
|
|
|
const { codecs } = param;
|
|
|
|
codecs.push({
|
|
payloadType: 2,
|
|
mimeType: `${kind}/piedpiper`,
|
|
clockRate: 1000,
|
|
channels: 2
|
|
});
|
|
|
|
return promise_rejects_dom(t, 'InvalidModificationError',
|
|
sender.setParameters(param));
|
|
}, `setParameters() with new codecs inserted should reject with InvalidModificationError (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
const param = sender.getParameters();
|
|
validateSenderRtpParameters(param);
|
|
|
|
const { codecs } = param;
|
|
codecs.pop();
|
|
|
|
return promise_rejects_dom(t, 'InvalidModificationError',
|
|
sender.setParameters(param));
|
|
}, `setParameters() with codecs removed should reject with InvalidModificationError (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
const param = sender.getParameters();
|
|
validateSenderRtpParameters(param);
|
|
|
|
const { codecs } = param;
|
|
codecs.reverse();
|
|
|
|
return promise_rejects_dom(t, 'InvalidModificationError',
|
|
sender.setParameters(param));
|
|
}, `setParameters() with codecs reordered should reject with InvalidModificationError (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
const param = sender.getParameters();
|
|
validateSenderRtpParameters(param);
|
|
|
|
delete param.codecs;
|
|
|
|
return promise_rejects_dom(t, 'InvalidModificationError',
|
|
sender.setParameters(param));
|
|
}, `setParameters() with codecs undefined should reject with InvalidModificationError (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
const sender1 = pc1.addTransceiver(kind).sender;
|
|
let param = sender1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No sender codecs in initial stable state');
|
|
|
|
const offer = await pc1.createOffer();
|
|
param = sender1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No sender codecs in initial stable state (after createOffer)');
|
|
|
|
await pc1.setLocalDescription(offer);
|
|
param = sender1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No sender codecs in initial have-local-offer');
|
|
|
|
await pc2.setRemoteDescription(offer);
|
|
const [sender2] = pc2.getSenders();
|
|
param = sender2.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No sender codecs in initial have-remote-offer');
|
|
|
|
const answer = await pc2.createAnswer();
|
|
param = sender2.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No sender codecs in initial have-remote-offer (after createAnswer)');
|
|
}, `RTCRtpSender.getParameters() should not have codecs before SDP negotiation completes (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
const receiver1 = pc1.addTransceiver(kind).receiver;
|
|
let param = receiver1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No receiver codecs in initial stable state');
|
|
|
|
const offer = await pc1.createOffer();
|
|
param = receiver1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No receiver codecs in initial stable state (after createOffer)');
|
|
|
|
await pc1.setLocalDescription(offer);
|
|
param = receiver1.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No receiver codecs in initial have-local-offer');
|
|
|
|
await pc2.setRemoteDescription(offer);
|
|
const [receiver2] = pc2.getReceivers();
|
|
param = receiver2.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No receiver codecs in initial have-remote-offer');
|
|
|
|
const answer = await pc2.createAnswer();
|
|
param = receiver2.getParameters();
|
|
assert_array_equals(param.codecs, [], 'No receiver codecs in initial have-remote-offer (after createAnswer)');
|
|
}, `RTCRtpReceiver.getParameters() should not have codecs before SDP negotiation completes (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
const sender1 = pc1.addTransceiver(kind).sender;
|
|
await exchangeOfferAnswer(pc1, pc2);
|
|
const [sender2] = pc2.getSenders();
|
|
|
|
let param = sender1.getParameters();
|
|
assert_array_field(param, 'codecs');
|
|
assert_not_equals(param.codecs.length, 0);
|
|
for (const codec of param.codecs) {
|
|
validateCodecParameters(codec);
|
|
}
|
|
|
|
param = sender2.getParameters();
|
|
assert_array_field(param, 'codecs');
|
|
assert_not_equals(param.codecs.length, 0);
|
|
for (const codec of param.codecs) {
|
|
validateCodecParameters(codec);
|
|
}
|
|
}, `RTCRtpSender.getParameters() should have codecs after negotiation (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
const receiver1 = pc1.addTransceiver(kind).receiver;
|
|
await exchangeOfferAnswer(pc1, pc2);
|
|
const [receiver2] = pc2.getReceivers();
|
|
|
|
let param = receiver1.getParameters();
|
|
assert_array_field(param, 'codecs');
|
|
assert_not_equals(param.codecs.length, 0);
|
|
for (const codec of param.codecs) {
|
|
validateCodecParameters(codec);
|
|
}
|
|
|
|
param = receiver2.getParameters();
|
|
assert_array_field(param, 'codecs');
|
|
assert_not_equals(param.codecs.length, 0);
|
|
for (const codec of param.codecs) {
|
|
validateCodecParameters(codec);
|
|
}
|
|
}, `RTCRtpReceiver.getParameters() should have codecs after negotiation (${kind})`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
|
|
const { sender } = pc.addTransceiver(kind);
|
|
await doOfferAnswerExchange(t, pc);
|
|
|
|
const {codecs} = pc.getReceivers()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(pc.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}, `RTCRtpReceiver.getParameters() codecs should match local SDP (${kind}, offerer)`);
|
|
|
|
promise_test(async t => {
|
|
const pc1 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc1.close());
|
|
const pc2 = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc2.close());
|
|
|
|
pc1.addTransceiver(kind);
|
|
await exchangeOfferAnswer(pc1, pc2);
|
|
|
|
const {codecs} = pc2.getReceivers()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}, `RTCRtpReceiver.getParameters() codecs should match local SDP (${kind}, answerer)`);
|
|
});
|
|
|
|
// SDP with unusual payload types and fmtp, and an unknown codec
|
|
const audioSdp = `v=0
|
|
o=- 166855176514521964 2 IN IP4 127.0.0.1
|
|
s=-
|
|
t=0 0
|
|
m=audio 9 UDP/TLS/RTP/SAVPF 121 111 0 101
|
|
c=IN IP4 0.0.0.0
|
|
a=rtcp:9 IN IP4 0.0.0.0
|
|
a=ice-ufrag:foobarba
|
|
a=ice-pwd:foobarba
|
|
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
|
|
a=setup:passive
|
|
a=mid:mid1
|
|
a=sendrecv
|
|
a=rtcp-rsize
|
|
a=rtpmap:101 telephone-event/8000/1
|
|
a=rtpmap:121 flarglblurp/8000/2
|
|
a=rtpmap:111 opus/48000/2
|
|
a=fmtp:111 maxaveragebitrate=20001;unknownparam=foo
|
|
`;
|
|
|
|
// SDP with unusual payload types and fmtp, and an unknown codec
|
|
const videoSdp = `v=0
|
|
o=- 1878890426675213188 2 IN IP4 127.0.0.1
|
|
s=-
|
|
t=0 0
|
|
m=video 9 UDP/TLS/RTP/SAVPF 116 117 120 124 119 123 122 121 118
|
|
c=IN IP4 0.0.0.0
|
|
a=sendrecv
|
|
a=fmtp:117 apt=116
|
|
a=fmtp:120 max-fs=12277;max-fr=50;unknownparam=foo
|
|
a=fmtp:124 apt=120
|
|
a=fmtp:119 max-fs=12266;max-fr=40
|
|
a=fmtp:123 apt=119
|
|
a=fmtp:118 apt=121
|
|
a=ice-pwd:60840251a559417c253d68478b0020fb
|
|
a=ice-ufrag:741347dd
|
|
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
|
|
a=setup:passive
|
|
a=mid:mid1
|
|
a=rtcp-mux
|
|
a=rtcp-rsize
|
|
a=rtpmap:116 flarglblurp/90000
|
|
a=rtpmap:117 rtx/90000
|
|
a=rtpmap:120 VP9/90000
|
|
a=rtpmap:124 rtx/90000
|
|
a=rtpmap:119 VP8/90000
|
|
a=rtpmap:123 rtx/90000
|
|
a=rtpmap:122 ulpfec/90000
|
|
a=rtpmap:121 red/90000
|
|
a=rtpmap:118 rtx/90000
|
|
`;
|
|
|
|
const remoteSdpParamsTests = [
|
|
{
|
|
description: 'audio, no fmtp checks',
|
|
kind: 'audio',
|
|
sdp: audioSdp,
|
|
expectedCodecs: [
|
|
{payloadType: 111, clockRate: 48000, channels: 2, mimeType: 'audio/opus'},
|
|
{payloadType: 0, clockRate: 8000, channels: 1, mimeType: 'audio/pcmu'},
|
|
{payloadType: 101, clockRate: 8000, channels: 1, mimeType: 'audio/telephone-event'},
|
|
]
|
|
},
|
|
|
|
{
|
|
description: 'audio, with fmtp checks',
|
|
kind: 'audio',
|
|
sdp: audioSdp,
|
|
expectedCodecs: [
|
|
{payloadType: 111, clockRate: 48000, channels: 2, mimeType: 'audio/opus', sdpFmtpLine: 'maxaveragebitrate=20001;unknownparam=foo'},
|
|
{payloadType: 0, clockRate: 8000, channels: 1, mimeType: 'audio/pcmu', sdpFmtpLine: undefined},
|
|
{payloadType: 101, clockRate: 8000, channels: 1, mimeType: 'audio/telephone-event', sdpFmtpLine: undefined},
|
|
]
|
|
},
|
|
|
|
{
|
|
description: 'video, minimal fmtp checks',
|
|
kind: 'video',
|
|
sdp: videoSdp,
|
|
expectedCodecs: [
|
|
{payloadType: 120, clockRate: 90000, mimeType: 'video/vp9'},
|
|
{payloadType: 124, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=120'},
|
|
{payloadType: 119, clockRate: 90000, mimeType: 'video/vp8'},
|
|
{payloadType: 123, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=119'},
|
|
{payloadType: 122, clockRate: 90000, mimeType: 'video/ulpfec'},
|
|
{payloadType: 121, clockRate: 90000, mimeType: 'video/red'},
|
|
{payloadType: 118, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=121'},
|
|
]
|
|
},
|
|
|
|
{
|
|
description: 'video, with fmtp checks',
|
|
kind: 'video',
|
|
sdp: videoSdp,
|
|
expectedCodecs: [
|
|
{payloadType: 120, clockRate: 90000, mimeType: 'video/vp9', sdpFmtpLine: 'max-fs=12277;max-fr=50;unknownparam=foo'},
|
|
{payloadType: 124, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=120'},
|
|
{payloadType: 119, clockRate: 90000, mimeType: 'video/vp8', sdpFmtpLine: 'max-fs=12266;max-fr=40'},
|
|
{payloadType: 123, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=119'},
|
|
{payloadType: 122, clockRate: 90000, mimeType: 'video/ulpfec', sdpFmtpLine: undefined},
|
|
{payloadType: 121, clockRate: 90000, mimeType: 'video/red', sdpFmtpLine: undefined},
|
|
{payloadType: 118, clockRate: 90000, mimeType: 'video/rtx', sdpFmtpLine: 'apt=121'},
|
|
]
|
|
},
|
|
];
|
|
|
|
remoteSdpParamsTests.forEach(test => {
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
|
|
pc.addTransceiver(test.kind, { direction: 'sendrecv'});
|
|
await pc.setLocalDescription();
|
|
const {sender, mid} = pc.getTransceivers()[0];
|
|
await pc.setRemoteDescription({sdp: test.sdp.replace('mid1', mid), type: 'answer'});
|
|
const {codecs} = sender.getParameters();
|
|
compareCodecParams(codecs, test.expectedCodecs);
|
|
}, `RTCRtpSender.getParameters() codecs should match remote SDP (${test.description}, offerer)`);
|
|
|
|
promise_test(async t => {
|
|
const pc = new RTCPeerConnection();
|
|
t.add_cleanup(() => pc.close());
|
|
|
|
await pc.setRemoteDescription({sdp: test.sdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
compareCodecParams(codecs, test.expectedCodecs);
|
|
}, `RTCRtpSender.getParameters() codecs should match remote SDP (${test.description}, answerer)`);
|
|
});
|
|
|
|
</script>
|