tor-browser

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

get_user_media.html (4046B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head><meta charset="UTF-8"></head>
      4 <body>
      5 <div id="message"></div>
      6 <button id="gum">getUserMedia</button>
      7 <script>
      8 // Specifies whether we are using fake streams to run this automation
      9 var useFakeStreams = true;
     10 try {
     11  var audioDevice = SpecialPowers.getCharPref("media.audio_loopback_dev");
     12  var videoDevice = SpecialPowers.getCharPref("media.video_loopback_dev");
     13  dump("TEST DEVICES: Using media devices:\n");
     14  dump("audio: " + audioDevice + "\nvideo: " + videoDevice + "\n");
     15  useFakeStreams = false;
     16 } catch (e) {
     17  dump("TEST DEVICES: No test devices found (in media.{audio,video}_loopback_dev, using fake streams.\n");
     18  useFakeStreams = true;
     19 }
     20 
     21 function message(m) {
     22  document.getElementById("message").innerHTML += `${m}<br>`;
     23  top.postMessage(m, "*");
     24 }
     25 
     26 var gStreams = [];
     27 var gVideoEvents = [];
     28 var gAudioEvents = [];
     29 
     30 /**
     31 * Queue a getUserMedia request to be triggered by a button click.
     32 * The button click needs to be handled by the caller.
     33 *
     34 * @param {boolean} aAudio - Whether to request audio.
     35 * @param {boolean} aVideo - Whether to request video.
     36 * @param {number} aShare - The type of screen sharing.
     37 * @param {boolean} aBadDevice - Whether to use a bad device ID.
     38 * @param {boolean} withUserActivation - Whether to simulate user activation.
     39 * @returns {Promise} - Resolves when the requestDevice call completes.
     40 */
     41 function queueRequestDeviceViaBtn(aAudio, aVideo, aShare, aBadDevice = false) {
     42  return new Promise((resolve) => {
     43    let button = document.getElementById("gum");
     44    button.addEventListener("click", () => {
     45      button.innerText = "getUserMedia";
     46      requestDevice(aAudio, aVideo, aShare, aBadDevice).then(resolve);
     47    }, {once: true});
     48    button.innerText =
     49      `getUserMedia(${aAudio}, ${aVideo}, ${aShare}, ${aBadDevice})`;
     50  });
     51 }
     52 
     53 async function requestDevice(aAudio, aVideo, aShare, aBadDevice = false) {
     54  const opts = {video: aVideo, audio: aAudio};
     55  if (aShare) {
     56    opts.video = { mediaSource: aShare };
     57    SpecialPowers.wrap(document).notifyUserGestureActivation();
     58  }
     59  if (useFakeStreams) {
     60    opts.fake = true;
     61  }
     62 
     63  if (aVideo && aBadDevice) {
     64    opts.video = {
     65      deviceId: "bad device",
     66    };
     67    opts.fake = true;
     68  }
     69 
     70  if (aAudio && aBadDevice) {
     71    opts.audio = {
     72      deviceId: "bad device",
     73    };
     74    opts.fake = true;
     75  }
     76 
     77  try {
     78    const stream = await navigator.mediaDevices.getUserMedia(opts)
     79    gStreams.push(stream);
     80 
     81    const videoTrack = stream.getVideoTracks()[0];
     82    if (videoTrack) {
     83      for (const name of ["mute", "unmute", "ended"]) {
     84        videoTrack.addEventListener(name, () => gVideoEvents.push(name));
     85      }
     86    }
     87 
     88    const audioTrack = stream.getAudioTracks()[0];
     89    if (audioTrack) {
     90      for (const name of ["mute", "unmute", "ended"]) {
     91        audioTrack.addEventListener(name, () => gAudioEvents.push(name));
     92      }
     93    }
     94    message("ok");
     95  } catch (err) {
     96    message("error: " + err);
     97  }
     98 }
     99 
    100 let selectedAudioOutputId;
    101 async function requestAudioOutput(options = {}) {
    102  const audioOutputOptions = options.requestSameDevice && {
    103    deviceId: selectedAudioOutputId,
    104  };
    105  SpecialPowers.wrap(document).notifyUserGestureActivation();
    106  try {
    107    ({ deviceId: selectedAudioOutputId } =
    108     await navigator.mediaDevices.selectAudioOutput(audioOutputOptions));
    109    message("ok");
    110  } catch (err) {
    111    message("error: " + err);
    112  }
    113 }
    114 
    115 message("pending");
    116 
    117 function stopTracks(aKind) {
    118  for (let stream of gStreams) {
    119    for (let track of stream.getTracks()) {
    120      if (track.kind == aKind) {
    121        track.stop();
    122        stream.removeTrack(track);
    123      }
    124    }
    125  }
    126  gStreams = gStreams.filter(s => !!s.getTracks().length);
    127  if (aKind == "video") {
    128    gVideoEvents = [];
    129  } else if (aKind == "audio") {
    130    gAudioEvents = [];
    131  }
    132 }
    133 
    134 function closeStream() {
    135  for (let stream of gStreams) {
    136    for (let track of stream.getTracks()) {
    137      track.stop();
    138    }
    139  }
    140  gStreams = [];
    141  gVideoEvents = [];
    142  gAudioEvents = [];
    143  message("closed");
    144 }
    145 </script>
    146 </body>
    147 </html>