feat(ui/tracker/player): small fixes feat(ui/tracker/player): fix incoming streams feat(tracker): some logs feat(tracker): fix types, fix stream binding feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): more stuff for multicall... feat(tracker): rm async feat(tracker): rewrite stuff feat(tracker): rewrite stuff feat(tracker): rewrite stuff feat(tracker): rewrite stuff feat(tracker): rewrite stuff feat(tracker): rewrite lstream feat(tracker): rewrite lstream feat(tracker): rewrite stuff feat(tracker): rewrite stuff feat(tracker): fix group call feat(tracker): fix group call feat(tracker): fix group call feat(tracker): fix group call feat(tracker): add text to ui feat(tracker): destroy calls obj on call end feat(tracker): rm unused prop fix(tracker-assist):simplify addRemoteStream logic fixup! fix(tracker-assist):simplify addRemoteStream logic refactor(tracker-assist): make multi-agents call logic more explicite => fixed few bugs
87 lines
2.5 KiB
TypeScript
87 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 = 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
|
|
console.error(e)
|
|
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>
|