tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rtp-headerextensions.html (4998B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>payload type handling (assuming rtcp-mux)</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="../third_party/sdp/sdp.js"></script>
      7 <script>
      8 'use strict';
      9 // Tests behaviour from https://www.rfc-editor.org/rfc/rfc8834.html#name-header-extensions
     10 
     11 function createOfferSdp(extmaps) {
     12  let sdp = `v=0
     13 o=- 0 3 IN IP4 127.0.0.1
     14 s=-
     15 t=0 0
     16 a=fingerprint:sha-256 A7:24:72:CA:6E:02:55:39:BA:66:DF:6E:CC:4C:D8:B0:1A:BF:1A:56:65:7D:F4:03:AD:7E:77:43:2A:29:EC:93
     17 a=ice-ufrag:6HHHdzzeIhkE0CKj
     18 a=ice-pwd:XYDGVpfvklQIEnZ6YnyLsAew
     19 `;
     20  sdp += 'a=group:BUNDLE ' + ['audio', 'video'].filter(kind => extmaps[kind]).join(' ') + '\r\n';
     21  if (extmaps.audio) {
     22    sdp += `m=audio 9 RTP/SAVPF 111
     23 c=IN IP4 0.0.0.0
     24 a=rtcp-mux
     25 a=sendonly
     26 a=mid:audio
     27 a=rtpmap:111 opus/48000/2
     28 a=setup:actpass
     29 ` + extmaps.audio.map(ext => SDPUtils.writeExtmap(ext)).join('');
     30  }
     31  if (extmaps.video) {
     32    sdp += `m=video 9 RTP/SAVPF 112
     33 c=IN IP4 0.0.0.0
     34 a=rtcp-mux
     35 a=sendonly
     36 a=mid:video
     37 a=rtpmap:112 VP8/90000
     38 a=setup:actpass
     39 ` + extmaps.video.map(ext => SDPUtils.writeExtmap(ext)).join('');
     40  }
     41  return sdp;
     42 }
     43 
     44 [
     45  // https://www.rfc-editor.org/rfc/rfc8834.html#section-5.2.4
     46  {
     47    audio: [{id: 1, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid'}],
     48    video: [{id: 1, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid'}],
     49    description: 'MID',
     50  },
     51  {
     52    // https://www.rfc-editor.org/rfc/rfc8834.html#section-5.2.2
     53    audio: [{id: 1, uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level'}],
     54    description: 'Audio level',
     55  },
     56  {
     57    // https://www.rfc-editor.org/rfc/rfc8834.html#section-5.2.5
     58    video: [{id: 1, uri: 'urn:3gpp:video-orientation'}],
     59    description: 'Video orientation',
     60  }
     61 ].forEach(testcase => {
     62  promise_test(async t => {
     63    const pc = new RTCPeerConnection();
     64    t.add_cleanup(() => pc.close());
     65 
     66    await pc.setRemoteDescription({type: 'offer', sdp: createOfferSdp(testcase)});
     67    const answer = await pc.createAnswer();
     68    const sections = SDPUtils.splitSections(answer.sdp);
     69    sections.shift();
     70    sections.forEach(section => {
     71      const rtpParameters = SDPUtils.parseRtpParameters(section);
     72      assert_equals(rtpParameters.headerExtensions.length, 1);
     73      assert_equals(rtpParameters.headerExtensions[0].id, testcase[SDPUtils.getKind(section)][0].id);
     74      assert_equals(rtpParameters.headerExtensions[0].uri, testcase[SDPUtils.getKind(section)][0].uri);
     75    });
     76  }, testcase.description + ' header extension is supported.');
     77 });
     78 
     79 promise_test(async t => {
     80  const pc = new RTCPeerConnection();
     81  t.add_cleanup(() => pc.close());
     82 
     83  pc.addTransceiver('video');
     84  const offer = await pc.createOffer();
     85  const section = SDPUtils.splitSections(offer.sdp)[1];
     86  const extensions = SDPUtils.matchPrefix(section, 'a=extmap:')
     87    .map(line => SDPUtils.parseExtmap(line));
     88  const extension_not_mid = extensions.find(e => e.uri !== 'urn:ietf:params:rtp-hdrext:sdes:mid');
     89  await pc.setRemoteDescription({type :'offer', sdp: offer.sdp.replace(extension_not_mid.uri, 'bogus')});
     90 
     91  await pc.setLocalDescription();
     92  const answer_section = SDPUtils.splitSections(pc.localDescription.sdp)[1];
     93  const answer_extensions = SDPUtils.matchPrefix(answer_section, 'a=extmap:')
     94    .map(line => SDPUtils.parseExtmap(line));
     95  assert_equals(answer_extensions.length, extensions.length - 1);
     96  assert_false(!!extensions.find(e => e.uri === 'bogus'));
     97  for (const answer_extension of answer_extensions) {
     98    assert_true(!!extensions.find(e => e.uri === answer_extension.uri));
     99  }
    100 }, 'Negotiates the subset of supported extensions offered');
    101 
    102 promise_test(async t => {
    103  const pc = new RTCPeerConnection();
    104  t.add_cleanup(() => pc.close());
    105 
    106  // Some implementations may refuse 15 as invalid id because of
    107  // https://www.rfc-editor.org/rfc/rfc8285#section-4.2
    108  // which only applies to one-byte extensions with ids 0-14.
    109  const sdp = createOfferSdp({audio: [{
    110    id: 15, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
    111  }]});
    112  await pc.setRemoteDescription({type: 'offer', sdp});
    113 }, 'Supports header extensions with id=15');
    114 
    115 promise_test(async t => {
    116  const pc = new RTCPeerConnection();
    117  t.add_cleanup(() => pc.close());
    118 
    119  const sdp = createOfferSdp({audio: [{
    120    id: 16, uri: 'urn:ietf:params:rtp-hdrext:sdes:mid',
    121  }, {
    122    id: 17, uri: 'urn:ietf:params:rtp-hdrext:ssrc-audio-level',
    123  }]});
    124  await pc.setRemoteDescription({type: 'offer', sdp});
    125  await pc.setLocalDescription();
    126  const answer_section = SDPUtils.splitSections(pc.localDescription.sdp)[1];
    127  const answer_extensions = SDPUtils.matchPrefix(answer_section, 'a=extmap:')
    128    .map(line => SDPUtils.parseExtmap(line));
    129  assert_equals(answer_extensions.length, 2);
    130  assert_true(!!answer_extensions.find(e => e.uri === 'urn:ietf:params:rtp-hdrext:sdes:mid'));
    131  assert_true(!!answer_extensions.find(e => e.uri === 'urn:ietf:params:rtp-hdrext:ssrc-audio-level'));
    132 }, 'Supports two-byte header extensions');
    133 </script>