100 lines
2.8 KiB
TypeScript
100 lines
2.8 KiB
TypeScript
import {Track} from "livekit-client"
|
|
import {MediaQuery} from "svelte/reactivity"
|
|
import {derived, get, writable} from "svelte/store"
|
|
import {currentVoiceSession, VoiceState, type VoiceSession, voiceState} from "@app/call/stores"
|
|
import {pushToast} from "@app/util/toast"
|
|
|
|
export enum VideoCallLayout {
|
|
Chat = "chat",
|
|
Video = "video",
|
|
Split = "split",
|
|
}
|
|
|
|
export const isDesktopLayout = new MediaQuery("min-width: 768px", false)
|
|
|
|
export enum ViewportSize {
|
|
Desktop = "desktop",
|
|
Mobile = "mobile",
|
|
}
|
|
|
|
export const videoCallViewportSync = {
|
|
previousLayout: undefined as ViewportSize | undefined,
|
|
}
|
|
|
|
export const videoCallLayout = writable<VideoCallLayout>(VideoCallLayout.Split)
|
|
|
|
export const resetVideoCallLayout = () => {
|
|
videoCallViewportSync.previousLayout = undefined
|
|
videoCallLayout.set(VideoCallLayout.Chat)
|
|
}
|
|
|
|
export const videoPrimaryTileKey = writable<string | undefined>(undefined)
|
|
|
|
export const toggleVideoPrimaryTile = (key: string) => {
|
|
videoPrimaryTileKey.update(k => (k === key ? undefined : key))
|
|
}
|
|
|
|
const VISUAL_SOURCES = [Track.Source.Camera, Track.Source.ScreenShare] as const
|
|
|
|
const countLiveVisualFeeds = (session: VoiceSession): number => {
|
|
const room = session.room
|
|
let n = 0
|
|
const lp = room.localParticipant
|
|
if (session.cameraOn) {
|
|
const pub = lp.getTrackPublication(Track.Source.Camera)
|
|
if (pub?.track) n += 1
|
|
}
|
|
if (session.screenShareOn) {
|
|
const pub = lp.getTrackPublication(Track.Source.ScreenShare)
|
|
if (pub?.track) n += 1
|
|
}
|
|
for (const rp of room.remoteParticipants.values()) {
|
|
for (const source of VISUAL_SOURCES) {
|
|
const pub = rp.getTrackPublication(source)
|
|
if (pub?.isSubscribed && pub.track) n += 1
|
|
}
|
|
}
|
|
return n
|
|
}
|
|
|
|
export const triggerVideoFeedCount = () => {
|
|
currentVoiceSession.update(s => (s ? {...s} : s))
|
|
}
|
|
|
|
export const videoTileCount = derived([currentVoiceSession, voiceState], ([$session, $state]) => {
|
|
if ($state !== VoiceState.Connected || !$session) return 0
|
|
return countLiveVisualFeeds($session)
|
|
})
|
|
|
|
export const toggleCamera = async () => {
|
|
const session = get(currentVoiceSession)
|
|
if (!session) return
|
|
|
|
const cameraOn = !session.cameraOn
|
|
try {
|
|
await session.room.localParticipant.setCameraEnabled(cameraOn)
|
|
currentVoiceSession.set({...session, cameraOn})
|
|
} catch {
|
|
pushToast({
|
|
theme: "error",
|
|
message: cameraOn ? "Could not access camera" : "Could not turn off camera",
|
|
})
|
|
}
|
|
}
|
|
|
|
export const toggleScreenShare = async () => {
|
|
const session = get(currentVoiceSession)
|
|
if (!session) return
|
|
|
|
const screenShareOn = !session.screenShareOn
|
|
try {
|
|
await session.room.localParticipant.setScreenShareEnabled(screenShareOn)
|
|
currentVoiceSession.set({...session, screenShareOn})
|
|
} catch {
|
|
pushToast({
|
|
theme: "error",
|
|
message: screenShareOn ? "Could not start screen sharing" : "Could not stop screen sharing",
|
|
})
|
|
}
|
|
}
|