rtx-codecs.https.html (4872B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>RTX codec integrity checks</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="../RTCPeerConnection-helper.js"></script> 7 <script src="../third_party/sdp/sdp.js"></script> 8 <script> 9 'use strict'; 10 11 // Tests for conformance to rules for RTX codecs. 12 // Basic rule: Offers and answers must contain RTX codecs, and the 13 // RTX codecs must have an a=fmtp line that points to a non-RTX codec. 14 15 // Helper function for doing one round of offer/answer exchange 16 // between two local peer connections. 17 // Calls setRemoteDescription(offer/answer) before 18 // setLocalDescription(offer/answer) to ensure the remote description 19 // is set and candidates can be added before the local peer connection 20 // starts generating candidates and ICE checks. 21 async function doSignalingHandshake(localPc, remotePc, options={}) { 22 let offer = await localPc.createOffer(); 23 // Modify offer if callback has been provided 24 if (options.modifyOffer) { 25 offer = await options.modifyOffer(offer); 26 } 27 28 // Apply offer. 29 await remotePc.setRemoteDescription(offer); 30 await localPc.setLocalDescription(offer); 31 32 let answer = await remotePc.createAnswer(); 33 // Modify answer if callback has been provided 34 if (options.modifyAnswer) { 35 answer = await options.modifyAnswer(answer); 36 } 37 38 // Apply answer. 39 await localPc.setRemoteDescription(answer); 40 await remotePc.setLocalDescription(answer); 41 } 42 43 function verifyRtxReferences(description) { 44 const mediaSection = SDPUtils.getMediaSections(description.sdp)[0]; 45 const rtpParameters = SDPUtils.parseRtpParameters(mediaSection); 46 for (const codec of rtpParameters.codecs) { 47 if (codec.name === 'rtx') { 48 assert_own_property(codec.parameters, 'apt', 'rtx codec has apt parameter'); 49 const referenced_codec = rtpParameters.codecs.find( 50 c => c.payloadType === parseInt(codec.parameters.apt)); 51 assert_true(referenced_codec !== undefined, `Found referenced codec`); 52 } 53 } 54 } 55 56 57 58 promise_test(async t => { 59 const pc = new RTCPeerConnection(); 60 const offer = await generateVideoReceiveOnlyOffer(pc); 61 verifyRtxReferences(offer); 62 }, 'Initial offer should have sensible RTX mappings'); 63 64 async function negotiateAndReturnAnswer(t) { 65 const pc1 = new RTCPeerConnection(); 66 const pc2 = new RTCPeerConnection(); 67 t.add_cleanup(() => pc1.close()); 68 t.add_cleanup(() => pc2.close()); 69 let [track, streams] = await getTrackFromUserMedia('video'); 70 const sender = pc1.addTrack(track); 71 await doSignalingHandshake(pc1, pc2); 72 return pc2.localDescription; 73 } 74 75 promise_test(async t => { 76 const answer = await negotiateAndReturnAnswer(t); 77 verifyRtxReferences(answer); 78 }, 'Self-negotiated answer should have sensible RTX parameters'); 79 80 promise_test(async t => { 81 const sampleOffer = `v=0 82 o=- 1878890426675213188 2 IN IP4 127.0.0.1 83 s=- 84 t=0 0 85 a=group:BUNDLE video 86 a=msid-semantic: WMS 87 m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 88 c=IN IP4 0.0.0.0 89 a=rtcp:9 IN IP4 0.0.0.0 90 a=ice-ufrag:RGPK 91 a=ice-pwd:rAyHEAKC7ckxQgWaRZXukz+Z 92 a=ice-options:trickle 93 a=fingerprint:sha-256 8C:29:0A:8F:11:06:BF:1C:58:B3:CA:E6:F1:F1:DC:99:4C:6C:89:E9:FF:BC:D4:38:11:18:1F:40:19:C8:49:37 94 a=setup:actpass 95 a=mid:video 96 a=recvonly 97 a=rtcp-mux 98 a=rtpmap:97 rtx/90000 99 a=fmtp:97 apt=98 100 a=rtpmap:98 VP8/90000 101 a=rtcp-fb:98 ccm fir 102 a=rtcp-fb:98 nack 103 a=rtcp-fb:98 nack pli 104 a=rtcp-fb:98 goog-remb 105 a=rtcp-fb:98 transport-cc 106 `; 107 const pc = new RTCPeerConnection(); 108 let [track, streams] = await getTrackFromUserMedia('video'); 109 const sender = pc.addTrack(track); 110 await pc.setRemoteDescription({type: 'offer', sdp: sampleOffer}); 111 const answer = await pc.createAnswer(); 112 verifyRtxReferences(answer); 113 }, 'A remote offer generates sensible RTX references in answer'); 114 115 promise_test(async t => { 116 const sampleOffer = `v=0 117 o=- 1878890426675213188 2 IN IP4 127.0.0.1 118 s=- 119 t=0 0 120 a=group:BUNDLE video 121 a=msid-semantic: WMS 122 m=video 9 UDP/TLS/RTP/SAVPF 96 97 98 99 123 c=IN IP4 0.0.0.0 124 a=rtcp:9 IN IP4 0.0.0.0 125 a=ice-ufrag:RGPK 126 a=ice-pwd:rAyHEAKC7ckxQgWaRZXukz+Z 127 a=ice-options:trickle 128 a=fingerprint:sha-256 8C:29:0A:8F:11:06:BF:1C:58:B3:CA:E6:F1:F1:DC:99:4C:6C:89:E9:FF:BC:D4:38:11:18:1F:40:19:C8:49:37 129 a=setup:actpass 130 a=mid:video 131 a=recvonly 132 a=rtcp-mux 133 a=rtpmap:96 VP8/90000 134 a=rtpmap:97 rtx/90000 135 a=fmtp:97 apt=98 136 a=rtpmap:98 VP8/90000 137 a=rtcp-fb:98 ccm fir 138 a=rtcp-fb:98 nack 139 a=rtcp-fb:98 nack pli 140 a=rtcp-fb:98 goog-remb 141 a=rtcp-fb:98 transport-cc 142 a=rtpmap:99 rtx/90000 143 a=fmtp:99 apt=96 144 `; 145 const pc = new RTCPeerConnection(); 146 let [track, streams] = await getTrackFromUserMedia('video'); 147 const sender = pc.addTrack(track); 148 await pc.setRemoteDescription({type: 'offer', sdp: sampleOffer}); 149 const answer = await pc.createAnswer(); 150 verifyRtxReferences(answer); 151 }, 'A remote offer with duplicate codecs generates sensible RTX references in answer'); 152 153 </script>