tor-browser

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

split.https.html (3839B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>RTCPeerConnection BUNDLE</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="/webrtc/third_party/sdp/sdp.js"></script>
      8 <script>
      9 'use strict';
     10 promise_test(async t => {
     11  const caller = new RTCPeerConnection();
     12  t.add_cleanup(() => caller.close());
     13  const calleeAudio = new RTCPeerConnection();
     14  t.add_cleanup(() => calleeAudio.close());
     15  const calleeVideo  = new RTCPeerConnection();
     16  t.add_cleanup(() => calleeVideo.close());
     17 
     18  const stream = await getNoiseStream({audio: true, video: true});
     19  t.add_cleanup(() => stream.getTracks().forEach(track => track.stop()));
     20  stream.getTracks().forEach(track => caller.addTrack(track, stream));
     21 
     22  let metadataToBeLoaded;
     23  calleeVideo.ontrack = (e) => {
     24    const stream = e.streams[0];
     25    const v = document.createElement('video');
     26    v.autoplay = true;
     27    v.srcObject = stream;
     28    v.id = stream.id
     29    metadataToBeLoaded = new Promise((resolve) => {
     30      v.addEventListener('loadedmetadata', () => {
     31        resolve();
     32      });
     33    });
     34  };
     35 
     36  caller.addEventListener('icecandidate', (e) => {
     37    // route depending on sdpMlineIndex
     38    if (e.candidate) {
     39      const target = e.candidate.sdpMLineIndex === 0 ? calleeAudio : calleeVideo;
     40      target.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
     41    } else {
     42      calleeAudio.addIceCandidate();
     43      calleeVideo.addIceCandidate();
     44    }
     45  });
     46  calleeAudio.addEventListener('icecandidate', (e) => {
     47    if (e.candidate) {
     48      caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
     49    }
     50    // Note: caller.addIceCandidate is only called for video to avoid calling it twice.
     51  });
     52  calleeVideo.addEventListener('icecandidate', (e) => {
     53    if (e.candidate) {
     54      caller.addIceCandidate({sdpMid: e.candidate.sdpMid, candidate: e.candidate.candidate});
     55    } else {
     56      caller.addIceCandidate();
     57    }
     58  });
     59 
     60  const offer = await caller.createOffer();
     61  const sections = SDPUtils.splitSections(offer.sdp);
     62  // Remove the a=group:BUNDLE from the SDP when signaling.
     63  const bundle = SDPUtils.matchPrefix(sections[0], 'a=group:BUNDLE')[0];
     64  sections[0] = sections[0].replace(bundle + '\r\n', '');
     65 
     66  const audioSdp = sections[0] + sections[1];
     67  const videoSdp = sections[0] + sections[2];
     68 
     69  await calleeAudio.setRemoteDescription({type: 'offer', sdp: audioSdp});
     70  await calleeVideo.setRemoteDescription({type: 'offer', sdp: videoSdp});
     71  await caller.setLocalDescription(offer);
     72 
     73  const answerAudio = await calleeAudio.createAnswer();
     74  const answerVideo = await calleeVideo.createAnswer();
     75  const audioSections = SDPUtils.splitSections(answerAudio.sdp);
     76  const videoSections = SDPUtils.splitSections(answerVideo.sdp);
     77 
     78  // Remove the fingerprint from the session part of the SDP if present
     79  // and move it to the media section.
     80  SDPUtils.matchPrefix(audioSections[0], 'a=fingerprint:').forEach(line => {
     81    audioSections[0] = audioSections[0].replace(line + '\r\n', '');
     82    audioSections[1] += line + '\r\n';
     83  });
     84  SDPUtils.matchPrefix(videoSections[0], 'a=fingerprint:').forEach(line => {
     85    videoSections[0] = videoSections[0].replace(line + '\r\n', '');
     86    videoSections[1] += line + '\r\n';
     87  });
     88 
     89  const sdp = audioSections[0] + audioSections[1] + videoSections[1];
     90  await caller.setRemoteDescription({type: 'answer', sdp});
     91  await calleeAudio.setLocalDescription(answerAudio);
     92  await calleeVideo.setLocalDescription(answerVideo);
     93 
     94  await metadataToBeLoaded;
     95  assert_equals(calleeAudio.connectionState, 'connected');
     96  assert_equals(calleeVideo.connectionState, 'connected');
     97 }, 'Connect audio and video to two independent PeerConnections');
     98 </script>