Add video settings to VoiceCallAudioSettingsDialog

This commit is contained in:
mplorentz
2026-04-03 09:23:53 -04:00
parent caf90b1167
commit ec8a632f6a
3 changed files with 47 additions and 8 deletions
@@ -26,8 +26,10 @@
let audioInputs = $state<MediaDeviceInfo[]>([]) let audioInputs = $state<MediaDeviceInfo[]>([])
let audioOutputs = $state<MediaDeviceInfo[]>([]) let audioOutputs = $state<MediaDeviceInfo[]>([])
let videoInputs = $state<MediaDeviceInfo[]>([])
let selectedInput = $state("") let selectedInput = $state("")
let selectedOutput = $state("") let selectedOutput = $state("")
let selectedVideo = $state("")
const loadDevices = async () => { const loadDevices = async () => {
if (!navigator.mediaDevices?.enumerateDevices) return if (!navigator.mediaDevices?.enumerateDevices) return
@@ -35,16 +37,25 @@
const devices = await navigator.mediaDevices.enumerateDevices() const devices = await navigator.mediaDevices.enumerateDevices()
audioInputs = devices.filter(d => d.kind === "audioinput") audioInputs = devices.filter(d => d.kind === "audioinput")
audioOutputs = devices.filter(d => d.kind === "audiooutput") audioOutputs = devices.filter(d => d.kind === "audiooutput")
videoInputs = devices.filter(d => d.kind === "videoinput")
} catch { } catch {
audioInputs = [] audioInputs = []
audioOutputs = [] audioOutputs = []
videoInputs = []
} }
} }
$effect(() => { $effect(() => {
loadDevices() void loadDevices()
navigator.mediaDevices?.addEventListener?.("devicechange", loadDevices) const md = navigator.mediaDevices
return () => navigator.mediaDevices?.removeEventListener?.("devicechange", loadDevices) if (!md?.addEventListener) return
const onDeviceChange = () => {
void loadDevices()
}
md.addEventListener("devicechange", onDeviceChange)
return () => {
md.removeEventListener("devicechange", onDeviceChange)
}
}) })
$effect(() => { $effect(() => {
@@ -55,6 +66,7 @@
} }
selectedInput = selectValueForActiveDevice(session, DeviceKind.AudioInput) selectedInput = selectValueForActiveDevice(session, DeviceKind.AudioInput)
selectedOutput = selectValueForActiveDevice(session, DeviceKind.AudioOutput) selectedOutput = selectValueForActiveDevice(session, DeviceKind.AudioOutput)
selectedVideo = selectValueForActiveDevice(session, DeviceKind.VideoInput)
}) })
const onInputChange = () => { const onInputChange = () => {
@@ -65,6 +77,10 @@
void switchVoiceActiveDevice(DeviceKind.AudioOutput, selectedOutput) void switchVoiceActiveDevice(DeviceKind.AudioOutput, selectedOutput)
} }
const onVideoChange = () => {
void switchVoiceActiveDevice(DeviceKind.VideoInput, selectedVideo)
}
const onDone = () => { const onDone = () => {
popModal() popModal()
} }
@@ -76,8 +92,8 @@
<Modal> <Modal>
<ModalBody> <ModalBody>
<ModalHeader> <ModalHeader>
<ModalTitle>Audio settings</ModalTitle> <ModalTitle>Call settings</ModalTitle>
<ModalSubtitle>Choose microphone and speaker for this call.</ModalSubtitle> <ModalSubtitle>Microphone, speaker, and camera for this call.</ModalSubtitle>
</ModalHeader> </ModalHeader>
<div class="flex flex-col gap-4 pt-2"> <div class="flex flex-col gap-4 pt-2">
<FieldInline> <FieldInline>
@@ -120,6 +136,25 @@
{/snippet} {/snippet}
</FieldInline> </FieldInline>
{/if} {/if}
<FieldInline>
{#snippet label()}
<p>Camera</p>
{/snippet}
{#snippet input()}
<select
class="select select-bordered w-full"
bind:value={selectedVideo}
onchange={onVideoChange}
aria-label="Camera">
<option value="">Default camera</option>
{#each videoInputs as d (d.deviceId)}
<option value={d.deviceId}>
{d.label || `Camera ${d.deviceId.slice(0, 8)}`}
</option>
{/each}
</select>
{/snippet}
</FieldInline>
</div> </div>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
+3 -3
View File
@@ -71,7 +71,7 @@
pushModal(VoiceRoomJoinDialog, {url: targetRoom.url, h: targetRoom.h}) pushModal(VoiceRoomJoinDialog, {url: targetRoom.url, h: targetRoom.h})
} }
const openAudioSettings = () => { const openCallSettings = () => {
pushModal(VoiceCallAudioSettingsDialog) pushModal(VoiceCallAudioSettingsDialog)
} }
</script> </script>
@@ -128,9 +128,9 @@
<Icon icon={Monitor} size={4} /> <Icon icon={Monitor} size={4} />
</Button> </Button>
<Button <Button
data-tip="Audio settings" data-tip="Call settings"
class="center tooltip tooltip-top btn btn-sm btn-square btn-ghost" class="center tooltip tooltip-top btn btn-sm btn-square btn-ghost"
onclick={openAudioSettings}> onclick={openCallSettings}>
<Icon icon={Settings} size={4} /> <Icon icon={Settings} size={4} />
</Button> </Button>
<Button <Button
+4
View File
@@ -54,6 +54,7 @@ const LIVEKIT_DEFAULT_DEVICE_ID = "default"
export enum DeviceKind { export enum DeviceKind {
AudioInput = "audioinput", AudioInput = "audioinput",
AudioOutput = "audiooutput", AudioOutput = "audiooutput",
VideoInput = "videoinput",
} }
export const switchVoiceActiveDevice = async ( export const switchVoiceActiveDevice = async (
@@ -74,6 +75,9 @@ export const switchVoiceActiveDevice = async (
case DeviceKind.AudioOutput: case DeviceKind.AudioOutput:
label = "speaker" label = "speaker"
break break
case DeviceKind.VideoInput:
label = "camera"
break
} }
pushToast({theme: "error", message: `Error changing ${label}`}) pushToast({theme: "error", message: `Error changing ${label}`})
} }