Merge feature/98-audio-settings-in-call into video-demo
Resolve VoiceWidget conflict: keep camera, screen share, and call settings. Extend join flow with optional camera on join and device picker. Add camera to in-call settings; rename UI to Call settings. Made-with: Cursor
This commit is contained in:
+55
-1
@@ -9,7 +9,9 @@ import {
|
||||
Room as LiveKitRoom,
|
||||
RoomEvent,
|
||||
Track,
|
||||
supportsAudioOutputSelection,
|
||||
type AudioCaptureOptions,
|
||||
type VideoCaptureOptions,
|
||||
} from "livekit-client"
|
||||
import {derived, get, writable} from "svelte/store"
|
||||
import {map, removeUndefined, uniqBy} from "@welshman/lib"
|
||||
@@ -25,6 +27,8 @@ export const LIVEKIT_PARTICIPANTS = 39004
|
||||
|
||||
export {checkRelayHasLivekit} from "$lib/livekit"
|
||||
|
||||
export {supportsAudioOutputSelection}
|
||||
|
||||
export type VoiceSession = {
|
||||
url: string
|
||||
h: string
|
||||
@@ -46,6 +50,40 @@ export enum VoiceState {
|
||||
|
||||
export const currentVoiceSession = writable<VoiceSession | undefined>(undefined)
|
||||
|
||||
const LIVEKIT_DEFAULT_DEVICE_ID = "default"
|
||||
|
||||
export enum DeviceKind {
|
||||
AudioInput = "audioinput",
|
||||
AudioOutput = "audiooutput",
|
||||
VideoInput = "videoinput",
|
||||
}
|
||||
|
||||
export const switchVoiceActiveDevice = async (
|
||||
kind: DeviceKind,
|
||||
targetDeviceId: string,
|
||||
): Promise<void> => {
|
||||
const session = get(currentVoiceSession)
|
||||
if (!session) return
|
||||
const id = targetDeviceId === "" ? LIVEKIT_DEFAULT_DEVICE_ID : targetDeviceId
|
||||
try {
|
||||
await session.room.switchActiveDevice(kind, id)
|
||||
} catch {
|
||||
let label: string
|
||||
switch (kind) {
|
||||
case DeviceKind.AudioInput:
|
||||
label = "microphone"
|
||||
break
|
||||
case DeviceKind.AudioOutput:
|
||||
label = "speaker"
|
||||
break
|
||||
case DeviceKind.VideoInput:
|
||||
label = "camera"
|
||||
break
|
||||
}
|
||||
pushToast({theme: "error", message: `Error changing ${label}`})
|
||||
}
|
||||
}
|
||||
|
||||
export const voiceState = writable<VoiceState>(VoiceState.Disconnected)
|
||||
|
||||
export const currentVoiceRoom = writable<Room | undefined>(undefined)
|
||||
@@ -253,6 +291,8 @@ export const joinVoiceRoom = async (
|
||||
h: string,
|
||||
startMuted = true,
|
||||
preferredMicId?: string,
|
||||
joinWithCamera = false,
|
||||
preferredCameraId?: string,
|
||||
): Promise<void> => {
|
||||
cancelJoinVoiceRoom()
|
||||
|
||||
@@ -303,12 +343,26 @@ export const joinVoiceRoom = async (
|
||||
|
||||
const muted = await setUpMicrophone(startMuted, preferredMicId, liveKitRoom.localParticipant)
|
||||
|
||||
let cameraOn = false
|
||||
if (joinWithCamera) {
|
||||
const videoCapture: VideoCaptureOptions | undefined = preferredCameraId
|
||||
? {deviceId: preferredCameraId}
|
||||
: undefined
|
||||
try {
|
||||
await liveKitRoom.localParticipant.setCameraEnabled(true, videoCapture)
|
||||
cameraOn = true
|
||||
bumpVideoCallLayoutRevision()
|
||||
} catch (e) {
|
||||
pushToast({theme: "error", message: "Could not access camera"})
|
||||
}
|
||||
}
|
||||
|
||||
currentVoiceSession.set({
|
||||
url,
|
||||
h,
|
||||
room: liveKitRoom,
|
||||
muted,
|
||||
cameraOn: false,
|
||||
cameraOn,
|
||||
screenShareOn: false,
|
||||
})
|
||||
voiceState.set(VoiceState.Connected)
|
||||
|
||||
Reference in New Issue
Block a user