1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
<!doctype html>
<meta charset=utf-8>
<title>RTCPeerConnection RTP extensions</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../third_party/sdp/sdp.js"></script>
<script>
'use strict';
async function setup() {
const pc1 = new RTCPeerConnection();
pc1.addTransceiver('audio');
// Make sure there is more than one rid, since there's no reason to use
// rtp-stream-id/repaired-rtp-stream-id otherwise. Some implementations
// may use them for unicast anyway, which isn't a spec violation, just
// a little silly.
pc1.addTransceiver('video', {sendEncodings: [{rid: '0'}, {rid: '1'}]});
const offer = await pc1.createOffer();
pc1.close();
return offer.sdp;
}
// Extensions that MUST be supported
const mandatoryExtensions = [
// Directly referenced in WebRTC RTP usage
'urn:ietf:params:rtp-hdrext:ssrc-audio-level', // RFC 8834 5.2.2
'urn:ietf:params:rtp-hdrext:sdes:mid', // RFC 8834 5.2.4
'urn:3gpp:video-orientation', // RFC 8834 5.2.5
// Required for support of simulcast with RID
'urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id', // RFC 8852 4.3
'urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id', // RFC 8852 4.4
];
// For further testing:
// - Add test for rapid synchronization - RFC 8834 5.2.1
// - Add test for encrypted header extensions (RFC 6904)
// - Separate tests for extensions in audio and video sections
for (const extension of mandatoryExtensions) {
promise_test(async t => {
const sdp = await setup();
const extensions = SDPUtils.matchPrefix(sdp, 'a=extmap:')
.map(SDPUtils.parseExtmap);
assert_true(!!extensions.find(ext => ext.uri === extension));
}, `RTP header extension ${extension} is present in offer`);
}
// Test for illegal remote behavior: Reassignment of hdrext ID
// in a subsequent offer/answer cycle.
promise_test(async t => {
const pc1 = new RTCPeerConnection();
t.add_cleanup(() => pc1.close());
const pc2 = new RTCPeerConnection();
t.add_cleanup(() => pc2.close());
pc1.addTransceiver('audio');
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
await pc2.setLocalDescription();
await pc1.setRemoteDescription(pc2.localDescription);
// Do a second offer/answer cycle.
await pc1.setLocalDescription();
await pc2.setRemoteDescription(pc1.localDescription);
const answer = await pc2.createAnswer();
// Swap the extension number of the two required extensions
answer.sdp = answer.sdp.replace('urn:ietf:params:rtp-hdrext:ssrc-audio-level',
'xyzzy')
.replace('urn:ietf:params:rtp-hdrext:sdes:mid',
'urn:ietf:params:rtp-hdrext:ssrc-audio-level')
.replace('xyzzy',
'urn:ietf:params:rtp-hdrext:sdes:mid');
return promise_rejects_dom(t, 'InvalidAccessError',
pc1.setRemoteDescription(answer));
}, 'RTP header extension reassignment causes failure');
</script>
|