diff --git a/toys/convulse/convulse.js b/toys/convulse/convulse.js index f7fc52a..6d52c17 100644 --- a/toys/convulse/convulse.js +++ b/toys/convulse/convulse.js @@ -35,8 +35,7 @@ class Convulse { document.querySelector("canvas").addEventListener("click", e => this.rec(e)) document.querySelector("#rec").addEventListener("click", e => this.rec(e)) - //document.querySelector("#save").addEventListener("click", e => this.save(e)) - + document.querySelector("#webcam-size").addEventListener("input", e => this.setWebcamSize(e)) document.querySelector("#webcam-size").value = localStorage.webcamSize || 0.3 document.querySelector("#webcam-size").dispatchEvent(new Event("input")) @@ -51,19 +50,34 @@ class Convulse { this.recorder = {state: "unstarted"} + // this.mediaStream gets audio directly from the device, video from canvas this.mediaStream = new MediaStream() - navigator.mediaDevices.getUserMedia({video: true, audio: true}) - .then(media => { - document.querySelector("#hello").classList.add("hidden") - this.webcamVideo.muted = true - this.webcamVideo.srcObject = media - this.webcamVideo.play() - for (let at of media.getAudioTracks()) { - this.mediaStream.addTrack(at) - console.log("Adding audio track", at) + // Populate select boxes with what media is available + navigator.mediaDevices.enumerateDevices() + .then(devs => { + for (let dev of devs) { + let opt = document.createElement("option") + opt.value = dev.deviceId + if (dev.kind == "audioinput") { + opt.text = dev.label || `Microphone ${aud.length+1}` + aud.appendChild(opt) + } else if (dev.kind == "videoinput") { + opt.text = dev.label || `Camera ${vid.length+1}` + vid.appendChild(opt) + } } }) + + // Pretend the user clicked whatever's in those boxes + let aud = document.querySelector("#audio-in") + let vid = document.querySelector("#video-in") + aud.addEventListener("change", e => this.inputSelect(e)) + vid.addEventListener("change", e => this.inputSelect(e)) + this.inputSelect() + + navigator.mediaDevices.getUserMedia({video: true, audio: true}) + .then(media => this.gotUserMedia(media)) .catch(err => { toast("Couldn't open camera!") }) @@ -81,7 +95,6 @@ class Convulse { let canvasStream = this.canvas.captureStream(30) for (let vt of canvasStream.getVideoTracks()) { this.mediaStream.addTrack(vt) - console.log("Adding video track", vt) } this.frame() @@ -89,6 +102,52 @@ class Convulse { toast("Click anywhere to start and stop recording") } + gotUserMedia(media) { + document.querySelector("#hello").classList.add("hidden") + + // Set video source + // sending this to an HTML element seems janky, is there no direct method for video? + if (this.webcamVideo.srcObject) { + for (let track of this.webcamVideo.srcObject.getTracks()) { + track.stop() + } + } + for (let track of media.getVideoTracks()) { + for (let opt of document.querySelector("#video-in")) { + if (opt.text == track.label) { + opt.selected = true + } + } + } + this.webcamVideo.muted = true + this.webcamVideo.srcObject = media + this.webcamVideo.play() + + // Set audio source + for (let track of this.mediaStream.getAudioTracks()) { + this.mediaStream.removeTrack(track) + track.stop() + } + for (let track of media.getAudioTracks()) { + this.mediaStream.addTrack(track) + for (let opt of document.querySelector("#audio-in")) { + opt.selected = (opt.value == track.deviceId) + } + } + } + + inputSelect(event) { + let audName = document.querySelector("#audio-in").value || undefined + let vidName = document.querySelector("#video-in").value || undefined + let constraints = { + audio: {deviceId: {exact: audName}}, + video: {deviceId: {exact: vidName}} + } + + navigator.mediaDevices.getUserMedia(constraints) + .then(e => this.gotUserMedia(e)) + } + setWebcamSize(event) { this.webcamSize = event.target.value localStorage.webcamSize = this.webcamSize diff --git a/toys/convulse/index.html b/toys/convulse/index.html index 185e15d..5361e59 100644 --- a/toys/convulse/index.html +++ b/toys/convulse/index.html @@ -38,6 +38,10 @@ 💾 +