import { get, writable, type Writable } from 'svelte/store'; const BASE_HEIGHT = 720; export enum MediaStreamStatusEnum { INIT = 'init', CONNECTED = 'connected', DISCONNECTED = 'disconnected' } export const onFrameChangeStore: Writable<{ blob: Blob }> = writable({ blob: new Blob() }); export const mediaDevices = writable([]); export const mediaStreamStatus = writable(MediaStreamStatusEnum.INIT); export const mediaStream = writable(null); export const mediaStreamActions = { async enumerateDevices() { // console.log("Enumerating devices"); await navigator.mediaDevices .enumerateDevices() .then((devices) => { const cameras = devices.filter((device) => device.kind === 'videoinput'); mediaDevices.set(cameras); }) .catch((err) => { console.error(err); }); }, async start(mediaDevicedID?: string, aspectRatio: number = 1) { const constraints = { audio: false, video: { width: { ideal: BASE_HEIGHT * aspectRatio }, height: { ideal: BASE_HEIGHT }, deviceId: mediaDevicedID } }; await navigator.mediaDevices .getUserMedia(constraints) .then((stream) => { mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED); mediaStream.set(stream); }) .catch((err) => { console.error(`${err.name}: ${err.message}`); mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED); mediaStream.set(null); }); }, async startScreenCapture() { const displayMediaOptions = { video: { displaySurface: 'window' }, audio: false, surfaceSwitching: 'include' }; let captureStream = null; try { captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions); const videoTrack = captureStream.getVideoTracks()[0]; console.log('Track settings:'); console.log(JSON.stringify(videoTrack.getSettings(), null, 2)); console.log('Track constraints:'); console.log(JSON.stringify(videoTrack.getConstraints(), null, 2)); mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED); mediaStream.set(captureStream); const capabilities = videoTrack.getCapabilities(); const aspectRatio = capabilities.aspectRatio; console.log('Aspect Ratio Constraints:', aspectRatio); } catch (err) { console.error(err); } }, async switchCamera(mediaDevicedID: string, aspectRatio: number) { console.log('Switching camera'); if (get(mediaStreamStatus) !== MediaStreamStatusEnum.CONNECTED) { return; } const constraints = { audio: false, video: { width: { ideal: BASE_HEIGHT * aspectRatio }, height: { ideal: BASE_HEIGHT }, deviceId: mediaDevicedID } }; console.log('Switching camera', constraints); await navigator.mediaDevices .getUserMedia(constraints) .then((stream) => { mediaStreamStatus.set(MediaStreamStatusEnum.CONNECTED); mediaStream.set(stream); }) .catch((err) => { console.error(`${err.name}: ${err.message}`); }); }, async stop() { navigator.mediaDevices.getUserMedia({ video: true }).then((stream) => { stream.getTracks().forEach((track) => track.stop()); }); mediaStreamStatus.set(MediaStreamStatusEnum.DISCONNECTED); mediaStream.set(null); } };