import { useEffect, useMemo, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { ArrowLeft, VideoOff } from 'lucide-react'; import { WindowControls } from '@/components/window-controls'; import { Button } from '@/components/ui/button'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Muted } from '@/components/ui/typography'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { AudioLevelBars } from '@/components/audio/audio-level-bars'; import { useAudioSource } from '@/components/audio/use-audio-source'; import { useMediaDevices } from '@/hooks/use-media-devices'; import { resolveEffectiveDeviceId, isSavedDeviceAvailable, } from '@/hooks/use-effective-device-id'; import { useMediaDevicesStore, type SavedDevice, } from '@/stores/media-devices-store'; const SYSTEM_DEFAULT = '__system_default__'; function usePreviewStream( enabled: boolean, micId: string | undefined, cameraId: string | undefined, cameraAvailable: boolean, ): { stream: MediaStream | null; error: string | null } { const [stream, setStream] = useState(null); const [error, setError] = useState(null); const [prevEnabled, setPrevEnabled] = useState(enabled); // Clear the preview when disabled; the effect below only manages the // getUserMedia subscription. if (enabled !== prevEnabled) { setPrevEnabled(enabled); if (!enabled) { setStream(null); setError(null); } } useEffect(() => { if (!enabled) return; let cancelled = false; let active: MediaStream | null = null; const audio: MediaTrackConstraints | boolean = micId ? { deviceId: { exact: micId } } : true; const video: MediaTrackConstraints | false = cameraAvailable ? cameraId ? { deviceId: { exact: cameraId }, aspectRatio: { ideal: 16 / 9 } } : { aspectRatio: { ideal: 16 / 9 } } : false; navigator.mediaDevices .getUserMedia({ audio, video }) .then((s) => { if (cancelled) { s.getTracks().forEach((t) => t.stop()); return; } active = s; setStream(s); setError(null); }) .catch((err: unknown) => { if (cancelled) return; setStream(null); setError( err instanceof Error ? err.message : 'Unable to access devices', ); }); return () => { cancelled = true; active?.getTracks().forEach((t) => t.stop()); }; }, [enabled, micId, cameraId, cameraAvailable]); return { stream, error }; } function deviceLabel(d: MediaDeviceInfo, index: number): string { if (d.label) return d.label; const kind = d.kind === 'audioinput' ? 'Microphone' : 'Camera'; return `${kind} ${index + 1}`; } function FieldLabel({ children }: { children: React.ReactNode }) { return ( ); } function InlineLevelMeter({ stream }: { stream: MediaStream | null }) { const audioSource = useAudioSource(stream); if (!audioSource) { return (
{[0, 1, 2].map((i) => (
))}
); } return (
); } function CameraPreview({ stream }: { stream: MediaStream | null }) { const videoRef = useRef(null); const hasVideoTrack = (stream?.getVideoTracks().length ?? 0) > 0; useEffect(() => { if (videoRef.current) { videoRef.current.srcObject = hasVideoTrack ? stream : null; } }, [stream, hasVideoTrack]); return (
{hasVideoTrack ? (
); } function DeviceSelect({ devices, saved, onChange, placeholder, }: { devices: MediaDeviceInfo[]; saved: SavedDevice | null; onChange: (d: SavedDevice | null) => void; placeholder: string; }) { const value = saved?.deviceId ?? SYSTEM_DEFAULT; return ( ); } export default function AudioVideoSettingsPage() { const navigate = useNavigate(); const { audioInputs, videoInputs, permissionState, requestLabels, error: deviceError, } = useMediaDevices(); const mic = useMediaDevicesStore((s) => s.mic); const camera = useMediaDevicesStore((s) => s.camera); const setMic = useMediaDevicesStore((s) => s.setMic); const setCamera = useMediaDevicesStore((s) => s.setCamera); const effectiveMicId = useMemo( () => resolveEffectiveDeviceId(mic, audioInputs), [mic, audioInputs], ); const effectiveCameraId = useMemo( () => resolveEffectiveDeviceId(camera, videoInputs), [camera, videoInputs], ); const cameraAvailable = videoInputs.length > 0; const permissionGranted = permissionState === 'granted'; const { stream, error: previewError } = usePreviewStream( permissionGranted, effectiveMicId, effectiveCameraId, cameraAvailable, ); const micUnavailable = permissionGranted && !isSavedDeviceAvailable(mic, audioInputs); const cameraUnavailable = permissionGranted && !isSavedDeviceAvailable(camera, videoInputs); return (
Audio & Video
{!permissionGranted && (

Allow device access

Grant permission to see device names and a live preview.
)} {/* Microphone */}
Microphone
{micUnavailable && ( Saved mic unavailable — using system default. )}
{/* Camera */}
Camera {cameraUnavailable && ( Saved camera unavailable — using system default. )}
{(previewError || (deviceError && permissionState === 'denied')) && ( {previewError ?? deviceError} )}
); }