import { SoundGroupNode, SoundGroupNodeOptions } from "./SoundGroupNode"; export interface TabSourceNodeOptions extends SoundGroupNodeOptions { } export class TabSourceNode extends SoundGroupNode { public readonly type = 'tabSource'; private stream?: MediaStream; private source?: MediaStreamAudioSourceNode; play() { if (!this.isPlaying) { this.setup() this.ctx.audioContext.resume(); } } private async setup() { try { this.stream = await navigator.mediaDevices.getDisplayMedia({ video: { displaySurface: "browser", frameRate: {ideal: 1} }, audio: { // @ts-ignore suppressLocalAudioPlayback: false, echoCancellation: false, noiseSuppression: false, sampleRate: 44100, }, preferCurrentTab: false, selfBrowserSurface: "exclude", systemAudio: "exclude", surfaceSwitching: "include", monitorTypeSurfaces: "include", }); console.log(this.stream); this.source = this.ctx.audioContext.createMediaStreamSource(this.stream); this.source.connect(this.gainNode); } catch (err) { console.error(err); } } stop() { this.stream?.getTracks().forEach(track => { track.stop(); }); this.source?.disconnect(); this.source = undefined; this.stream = undefined; } get isPlaying(): boolean { return !!(this.stream && this.source); } togglePlay(): void { if (this.isPlaying) { this.stop(); } else { this.play(); } } serializeOptions() { return { ...super.serializeOptions(), type: this.type, } as const; } }