openreplay/frontend/app/player/MessageDistributor/managers/LocalStream.ts

85 lines
2.5 KiB
TypeScript

declare global {
interface HTMLCanvasElement {
captureStream(frameRate?: number): MediaStream;
}
}
function dummyTrack(): MediaStreamTrack {
const canvas = document.createElement("canvas")//, { width: 0, height: 0})
canvas.width=canvas.height=2 // Doesn't work when 1 (?!)
const ctx = canvas.getContext('2d');
ctx?.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(function draw(){
ctx?.fillRect(0,0, canvas.width, canvas.height)
requestAnimationFrame(draw);
});
// Also works. Probably it should be done once connected.
//setTimeout(() => { ctx?.fillRect(0,0, canvas.width, canvas.height) }, 4000)
return canvas.captureStream(60).getTracks()[0];
}
export default function RequestLocalStream(): Promise<LocalStream> {
return navigator.mediaDevices.getUserMedia({ audio:true })
.then(aStream => {
const aTrack = aStream.getAudioTracks()[0]
if (!aTrack) { throw new Error("No audio tracks provided") }
return new _LocalStream(aTrack)
})
}
class _LocalStream {
private mediaRequested: boolean = false
readonly stream: MediaStream
private readonly vdTrack: MediaStreamTrack
constructor(aTrack: MediaStreamTrack) {
this.vdTrack = dummyTrack()
this.stream = new MediaStream([ aTrack, this.vdTrack ])
}
toggleVideo(): Promise<boolean> {
if (!this.mediaRequested) {
return navigator.mediaDevices.getUserMedia({video:true})
.then(vStream => {
const vTrack = vStream.getVideoTracks()[0]
if (!vTrack) {
throw new Error("No video track provided")
}
this.stream.addTrack(vTrack)
this.stream.removeTrack(this.vdTrack)
this.mediaRequested = true
if (this.onVideoTrackCb) {
this.onVideoTrackCb(vTrack)
}
return true
})
.catch(e => {
// TODO: log
return false
})
}
let enabled = true
this.stream.getVideoTracks().forEach(track => {
track.enabled = enabled = enabled && !track.enabled
})
return Promise.resolve(enabled)
}
toggleAudio(): boolean {
let enabled = true
this.stream.getAudioTracks().forEach(track => {
track.enabled = enabled = enabled && !track.enabled
})
return enabled
}
private onVideoTrackCb: ((t: MediaStreamTrack) => void) | null = null
onVideoTrack(cb: (t: MediaStreamTrack) => void) {
this.onVideoTrackCb = cb
}
stop() {
this.stream.getTracks().forEach(t => t.stop())
}
}
export type LocalStream = InstanceType<typeof _LocalStream>