391 lines
14 KiB
HTML
391 lines
14 KiB
HTML
<!DOCTYPE HTML>
|
|
<html>
|
|
|
|
<head>
|
|
<script type="application/javascript" src="pc.js"></script>
|
|
<script type="application/javascript" src="sdpUtils.js"></script>
|
|
<script type="application/javascript" src="helpers_from_wpt/sdp.js"></script>
|
|
</head>
|
|
|
|
<body>
|
|
<pre id="test">
|
|
<script type="application/javascript">
|
|
createHTML({
|
|
bug: "1534687",
|
|
title: "getParameters tests (that we can't do in wpt)",
|
|
visible: true
|
|
});
|
|
|
|
function compareCodecParam(observed, expected) {
|
|
info(`Comparing ${JSON.stringify(observed)} to ${JSON.stringify(expected)}`);
|
|
is(observed.payloadType, expected.payloadType);
|
|
is(observed.clockRate, expected.clockRate);
|
|
is(observed.channels, expected.channels);
|
|
is(observed.mimeType.toLowerCase(), expected.mimeType.toLowerCase());
|
|
if (expected.hasOwnProperty('sdpFmtpLine')) {
|
|
is(observed.sdpFmtpLine, expected.sdpFmtpLine);
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
is(codecs.length, rtpParameters.codecs.length);
|
|
isnot(codecs.length, 0);
|
|
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);
|
|
}
|
|
}
|
|
|
|
function getNumExpectedH264SendCodecs() {
|
|
if (!navigator.userAgent.includes("Android")) {
|
|
// Constrained Baseline and Baseline multiplied with packetization-mode 0 and 1.
|
|
return 4;
|
|
}
|
|
// packetization-mode=0 is not supported with MediaDataEncoder, which is
|
|
// the only encoder on Android.
|
|
return 2;
|
|
}
|
|
|
|
// SDP with unusual values in fmtp, but in the same formatting that Firefox
|
|
// typically uses. This lets us check that we're putting the right param values
|
|
// in sdpFmtpLine, if not what appears in the SDP verbatim.
|
|
const audioSdp = `v=0
|
|
o=- 1878890426675213188 2 IN IP4 127.0.0.1
|
|
s=-
|
|
t=0 0
|
|
a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
|
|
m=audio 9 UDP/TLS/RTP/SAVPF 109 9 0 8 101
|
|
c=IN IP4 0.0.0.0
|
|
a=sendrecv
|
|
a=fmtp:109 maxplaybackrate=48001;stereo=0;useinbandfec=0
|
|
a=fmtp:101 0-14
|
|
a=ice-pwd:60840251a559417c253d68478b0020fb
|
|
a=ice-ufrag:741347dd
|
|
a=mid:0
|
|
a=msid:{0df6a81e-d3f8-4d0f-ab93-892762bd2af7} {b15b10a1-061b-4685-9ca4-99e110744b2e}
|
|
a=rtcp-mux
|
|
a=rtpmap:109 opus/48000/2
|
|
a=rtpmap:9 G722/8000/1
|
|
a=rtpmap:0 PCMU/8000
|
|
a=rtpmap:8 PCMA/8000
|
|
a=rtpmap:101 telephone-event/8000/1
|
|
a=setup:passive
|
|
`;
|
|
|
|
let videoSdp;
|
|
if (navigator.userAgent.includes("Android")) {
|
|
// Alternate form with no packetization-mode=0 h264
|
|
videoSdp = `v=0
|
|
o=- 1878890426675213188 2 IN IP4 127.0.0.1
|
|
s=-
|
|
t=0 0
|
|
a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
|
|
m=video 9 UDP/TLS/RTP/SAVPF 121 125 120 124 126 127 105 106 123 122 119
|
|
c=IN IP4 0.0.0.0
|
|
a=sendonly
|
|
a=fmtp:126 profile-level-id=42e00b;level-asymmetry-allowed=1;packetization-mode=1
|
|
a=fmtp:105 profile-level-id=420015;level-asymmetry-allowed=1;packetization-mode=1
|
|
a=fmtp:121 max-fs=12277;max-fr=50
|
|
a=fmtp:125 apt=121
|
|
a=fmtp:127 apt=126
|
|
a=fmtp:106 apt=105
|
|
a=fmtp:120 max-fs=12266;max-fr=40
|
|
a=fmtp:124 apt=120
|
|
a=fmtp:119 apt=122
|
|
a=ice-pwd:60840251a559417c253d68478b0020fb
|
|
a=ice-ufrag:741347dd
|
|
a=mid:0
|
|
a=msid:{debeb004-97f0-44ca-b6b2-a6bd8e42ddb2} {7fcd72c7-b112-49b4-892c-feee2cc9525d}
|
|
a=rtcp-mux
|
|
a=rtcp-rsize
|
|
a=rtpmap:121 VP9/90000
|
|
a=rtpmap:125 rtx/90000
|
|
a=rtpmap:120 VP8/90000
|
|
a=rtpmap:124 rtx/90000
|
|
a=rtpmap:126 H264/90000
|
|
a=rtpmap:127 rtx/90000
|
|
a=rtpmap:105 H264/90000
|
|
a=rtpmap:106 rtx/90000
|
|
a=rtpmap:123 ulpfec/90000
|
|
a=rtpmap:122 red/90000
|
|
a=rtpmap:119 rtx/90000
|
|
a=setup:passive
|
|
`;
|
|
} else {
|
|
videoSdp = `v=0
|
|
o=- 1878890426675213188 2 IN IP4 127.0.0.1
|
|
s=-
|
|
t=0 0
|
|
a=fingerprint:sha-256 EB:74:E9:5F:EB:FB:79:D4:36:3A:06:89:DD:49:D0:C7:A5:EA:2A:B2:38:74:C8:AF:E4:A0:5A:EF:A9:58:B5:1A
|
|
m=video 9 UDP/TLS/RTP/SAVPF 121 125 120 124 126 127 97 98 105 106 103 104 123 122 119
|
|
c=IN IP4 0.0.0.0
|
|
a=sendonly
|
|
a=fmtp:126 profile-level-id=42e00b;level-asymmetry-allowed=1;packetization-mode=1
|
|
a=fmtp:97 profile-level-id=42e00b;level-asymmetry-allowed=1
|
|
a=fmtp:105 profile-level-id=420015;level-asymmetry-allowed=1;packetization-mode=1
|
|
a=fmtp:103 profile-level-id=420015;level-asymmetry-allowed=1
|
|
a=fmtp:121 max-fs=12277;max-fr=50
|
|
a=fmtp:125 apt=121
|
|
a=fmtp:120 max-fs=12266;max-fr=40
|
|
a=fmtp:124 apt=120
|
|
a=fmtp:127 apt=126
|
|
a=fmtp:98 apt=97
|
|
a=fmtp:106 apt=105
|
|
a=fmtp:104 apt=103
|
|
a=fmtp:100 apt=99
|
|
a=fmtp:119 apt=122
|
|
a=ice-pwd:60840251a559417c253d68478b0020fb
|
|
a=ice-ufrag:741347dd
|
|
a=mid:0
|
|
a=msid:{debeb004-97f0-44ca-b6b2-a6bd8e42ddb2} {7fcd72c7-b112-49b4-892c-feee2cc9525d}
|
|
a=rtcp-mux
|
|
a=rtcp-rsize
|
|
a=rtpmap:121 VP9/90000
|
|
a=rtpmap:125 rtx/90000
|
|
a=rtpmap:120 VP8/90000
|
|
a=rtpmap:124 rtx/90000
|
|
a=rtpmap:126 H264/90000
|
|
a=rtpmap:127 rtx/90000
|
|
a=rtpmap:97 H264/90000
|
|
a=rtpmap:98 rtx/90000
|
|
a=rtpmap:105 H264/90000
|
|
a=rtpmap:106 rtx/90000
|
|
a=rtpmap:103 H264/90000
|
|
a=rtpmap:104 rtx/90000
|
|
a=rtpmap:123 ulpfec/90000
|
|
a=rtpmap:122 red/90000
|
|
a=rtpmap:119 rtx/90000
|
|
a=setup:passive
|
|
`;
|
|
}
|
|
|
|
let tests = [
|
|
// fmtp testing in wpt requires a verbatim match, which we do not support
|
|
// yet (see bug 1751671). These test that we have a semantic match at least,
|
|
// because the sdp's fmtps use the same formatting that Firefox uses.
|
|
// TODO(https://bugzilla.mozilla.org/show_bug.cgi?id=1751671)
|
|
async function checkSenderFmtpAudioAnswerer() {
|
|
const pc = new RTCPeerConnection();
|
|
await pc.setRemoteDescription({sdp: audioSdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(audioSdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
},
|
|
|
|
async function checkSenderFmtpVideoAnswerer() {
|
|
const pc = new RTCPeerConnection();
|
|
await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(videoSdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
},
|
|
|
|
async function checkSenderFmtpAudioOfferer() {
|
|
const pc = new RTCPeerConnection();
|
|
pc.addTransceiver('audio', { direction: 'sendrecv' });
|
|
await pc.setLocalDescription();
|
|
await pc.setRemoteDescription({sdp: audioSdp, type: 'answer'});
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(audioSdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
},
|
|
|
|
async function checkSenderFmtpVideoOfferer() {
|
|
const pc = new RTCPeerConnection();
|
|
pc.addTransceiver('video', { direction: 'sendrecv' });
|
|
await pc.setLocalDescription();
|
|
await pc.setRemoteDescription({sdp: videoSdp, type: 'answer'});
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
const sections = SDPUtils.splitSections(videoSdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
},
|
|
|
|
// wpt does not allow us to test that .codecs omits things that the pref
|
|
// system has disabled
|
|
async function checkRedUlpfecDisabled() {
|
|
await withPrefs([["media.navigator.video.red_ulpfec_enabled", false]], async () => {
|
|
const pc = new RTCPeerConnection();
|
|
await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
// Control
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
|
|
// No red or ulpfec
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/red'), false);
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/ulpfec'), false);
|
|
}
|
|
);
|
|
},
|
|
|
|
async function checkRtxDisabled() {
|
|
await withPrefs([["media.peerconnection.video.use_rtx", false]], async () => {
|
|
const pc = new RTCPeerConnection();
|
|
await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
// Control
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
|
|
// No rtx
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/rtx'), false);
|
|
}
|
|
);
|
|
},
|
|
|
|
async function checkVP9Disabled() {
|
|
await withPrefs([["media.peerconnection.video.vp9_enabled", false]], async () => {
|
|
const pc = new RTCPeerConnection();
|
|
await pc.setRemoteDescription({sdp: videoSdp, type: 'offer'});
|
|
await pc.setLocalDescription();
|
|
const {codecs} = pc.getSenders()[0].getParameters();
|
|
// Control
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp8'), true);
|
|
// No VP9
|
|
is(codecs.some(c => c.mimeType.toLowerCase() == 'video/vp9'), false);
|
|
}
|
|
);
|
|
},
|
|
|
|
async function checkH264Sender() {
|
|
const numExpectedH264Codecs = getNumExpectedH264SendCodecs();
|
|
const pc1 = new RTCPeerConnection();
|
|
const pc2 = new RTCPeerConnection();
|
|
const {sender} = pc1.addTransceiver('video');
|
|
await pc1.setLocalDescription();
|
|
await pc2.setRemoteDescription(pc1.localDescription);
|
|
await pc2.setLocalDescription();
|
|
await pc1.setRemoteDescription(pc2.localDescription);
|
|
{
|
|
const {codecs} = pc1.getSenders()[0].getParameters();
|
|
info("pc1 codecs: " + JSON.stringify(codecs, null, 2));
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc1.remoteDescription.sdp);
|
|
info("pc1 msection: " + sections[1].replace(/\r\n/g, "\n"));
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
|
|
{
|
|
const {codecs} = pc2.getSenders()[0].getParameters();
|
|
info("pc2 codecs: " + JSON.stringify(codecs, null, 2));
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc2.remoteDescription.sdp);
|
|
info("pc2 msection: " + sections[1].replace(/\r\n/g, "\n"));
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
},
|
|
|
|
async function checkH264Receiver() {
|
|
const numExpectedH264Codecs = getNumExpectedH264SendCodecs();
|
|
const pc1 = new RTCPeerConnection();
|
|
const pc2 = new RTCPeerConnection();
|
|
pc1.addTransceiver('video');
|
|
await pc1.setLocalDescription();
|
|
await pc2.setRemoteDescription(pc1.localDescription);
|
|
await pc2.setLocalDescription();
|
|
await pc1.setRemoteDescription(pc2.localDescription);
|
|
{
|
|
const {codecs} = pc1.getReceivers()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
|
|
{
|
|
const {codecs} = pc2.getReceivers()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
},
|
|
|
|
async function checkH264NoLevelAsymmetryInOffer() {
|
|
const numExpectedH264Codecs = getNumExpectedH264SendCodecs();
|
|
const pc1 = new RTCPeerConnection();
|
|
const pc2 = new RTCPeerConnection();
|
|
pc1.addTransceiver('video');
|
|
await pc1.setLocalDescription();
|
|
const mungedOffer = {
|
|
sdp: pc1.localDescription.sdp.replace(/level-asymmetry-allowed=1/g, 'level-asymmetry-allowed=0'),
|
|
type: 'offer'
|
|
};
|
|
await pc2.setRemoteDescription(mungedOffer);
|
|
await pc2.setLocalDescription();
|
|
{
|
|
const {codecs} = pc2.getSenders()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc2.remoteDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
|
|
{
|
|
const {codecs} = pc2.getReceivers()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc2.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
},
|
|
|
|
async function checkH264NoLevelAsymmetryInAnswer() {
|
|
const numExpectedH264Codecs = getNumExpectedH264SendCodecs();
|
|
const pc1 = new RTCPeerConnection();
|
|
const pc2 = new RTCPeerConnection();
|
|
pc1.addTransceiver('video');
|
|
await pc1.setLocalDescription();
|
|
await pc2.setRemoteDescription(pc1.localDescription);
|
|
await pc2.setLocalDescription();
|
|
const mungedAnswer = {
|
|
sdp: pc2.localDescription.sdp.replace(/level-asymmetry-allowed=1/g, 'level-asymmetry-allowed=0'),
|
|
type: 'answer'
|
|
};
|
|
await pc1.setRemoteDescription(mungedAnswer);
|
|
{
|
|
const {codecs} = pc1.getSenders()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc1.remoteDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
|
|
{
|
|
const {codecs} = pc1.getReceivers()[0].getParameters();
|
|
is(codecs.filter(c => c.mimeType.toLowerCase() == 'video/h264').length, numExpectedH264Codecs);
|
|
const sections = SDPUtils.splitSections(pc1.localDescription.sdp);
|
|
checkCodecsAgainstSDP(codecs, sections[1]);
|
|
}
|
|
},
|
|
];
|
|
|
|
runNetworkTest(async () => {
|
|
await SpecialPowers.pushPrefEnv({ set: [["media.navigator.video.disable_h264_baseline", false]] });
|
|
for (const test of tests) {
|
|
info(`Running test: ${test.name}`);
|
|
await test();
|
|
info(`Done running test: ${test.name}`);
|
|
}
|
|
});
|
|
|
|
</script>
|
|
</pre>
|
|
</body>
|
|
</html>
|