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>