tor-browser

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

RTCRtpSynchronizationSource-helper.js (4316B)


      1 'use strict';
      2 
      3 // This file depends on `webrtc/RTCPeerConnection-helper.js`
      4 // which should be loaded from the main HTML file.
      5 
      6 var kAbsCaptureTime =
      7    'http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time';
      8 
      9 function addHeaderExtensionToSdp(sdp, uri) {
     10  // Find the highest used header extension id by sorting the extension ids used,
     11  // eliminating duplicates and adding one. This is not quite correct
     12  // but this code will go away with the header extension API.
     13  const usedIds = sdp.split('\n')
     14    .filter(line => line.startsWith('a=extmap:'))
     15    .map(line => parseInt(line.split(' ')[0].substring(9), 10))
     16    .sort((a, b) => a - b)
     17    .filter((item, index, array) => array.indexOf(item) === index);
     18  const nextId = usedIds[usedIds.length - 1] + 1;
     19  const extmapLine = 'a=extmap:' + nextId + ' ' + uri + '\r\n';
     20 
     21  const sections = sdp.split('\nm=').map((part, index) => {
     22    return (index > 0 ? 'm=' + part : part).trim() + '\r\n';
     23  });
     24  const sessionPart = sections.shift();
     25  return sessionPart + sections.map(mediaSection => mediaSection + extmapLine).join('');
     26 }
     27 
     28 // TODO(crbug.com/1051821): Use RTP header extension API instead of munging
     29 // when the RTP header extension API is implemented.
     30 async function addAbsCaptureTimeAndExchangeOffer(caller, callee) {
     31  let offer = await caller.createOffer();
     32 
     33  // Absolute capture time header extension may not be offered by default,
     34  // in such case, munge the SDP.
     35  offer.sdp = addHeaderExtensionToSdp(offer.sdp, kAbsCaptureTime);
     36 
     37  await caller.setLocalDescription(offer);
     38  return callee.setRemoteDescription(offer);
     39 }
     40 
     41 // TODO(crbug.com/1051821): Use RTP header extension API instead of munging
     42 // when the RTP header extension API is implemented.
     43 async function checkAbsCaptureTimeAndExchangeAnswer(caller, callee,
     44                                                    absCaptureTimeAnswered) {
     45  let answer = await callee.createAnswer();
     46 
     47  const extmap = new RegExp('a=extmap:\\d+ ' + kAbsCaptureTime + '\r\n', 'g');
     48  if (answer.sdp.match(extmap) == null) {
     49    // We expect that absolute capture time RTP header extension is answered.
     50    // But if not, there is no need to proceed with the test.
     51    assert_false(absCaptureTimeAnswered, 'Absolute capture time RTP ' +
     52        'header extension is not answered');
     53  } else {
     54    if (!absCaptureTimeAnswered) {
     55      // We expect that absolute capture time RTP header extension is not
     56      // answered, but it is, then we munge the answer to remove it.
     57      answer.sdp = answer.sdp.replace(extmap, '');
     58    }
     59  }
     60 
     61  await callee.setLocalDescription(answer);
     62  return caller.setRemoteDescription(answer);
     63 }
     64 
     65 async function exchangeOfferAndListenToOntrack(t, caller, callee,
     66                                               absCaptureTimeOffered) {
     67  const ontrackPromise = addEventListenerPromise(t, callee, 'track');
     68  // Absolute capture time header extension is expected not offered by default,
     69  // and thus munging is needed to enable it.
     70  await absCaptureTimeOffered
     71      ? addAbsCaptureTimeAndExchangeOffer(caller, callee)
     72      : exchangeOffer(caller, callee);
     73  return ontrackPromise;
     74 }
     75 
     76 async function initiateSingleTrackCall(t, cap, absCaptureTimeOffered,
     77                                       absCaptureTimeAnswered) {
     78  const caller = new RTCPeerConnection();
     79  t.add_cleanup(() => caller.close());
     80  const callee = new RTCPeerConnection();
     81  t.add_cleanup(() => callee.close());
     82 
     83  const stream = await getNoiseStream(cap);
     84  stream.getTracks().forEach(track => {
     85    caller.addTrack(track, stream);
     86    t.add_cleanup(() => track.stop());
     87  });
     88 
     89  // TODO(crbug.com/988432): `getSynchronizationSources() on the audio side
     90  // needs a hardware sink for the returned dictionary entries to get updated.
     91  const remoteVideo = document.getElementById('remote');
     92 
     93  callee.ontrack = e => {
     94    remoteVideo.srcObject = e.streams[0];
     95  }
     96 
     97  exchangeIceCandidates(caller, callee);
     98 
     99  await exchangeOfferAndListenToOntrack(t, caller, callee,
    100                                        absCaptureTimeOffered);
    101 
    102  // Exchange answer and check whether the absolute capture time RTP header
    103  // extension is answered.
    104  await checkAbsCaptureTimeAndExchangeAnswer(caller, callee,
    105                                             absCaptureTimeAnswered);
    106 
    107  return [caller, callee];
    108 }