'use client'; import * as React from 'react'; import { useMaybeLayoutContext, MediaDeviceMenu, useRoomContext, useIsRecording, } from '@livekit/components-react'; import styles from '../styles/SettingsMenu.module.css'; import { CameraSettings } from './CameraSettings'; import { MicrophoneSettings } from './MicrophoneSettings'; import { useSettingsState } from './SettingsContext'; import { KeyBinding, KeyCommand } from './types'; import { keybindingOptions } from './keybindings'; /** * @alpha */ export interface SettingsMenuProps extends React.HTMLAttributes {} /** * @alpha */ export function SettingsMenu(props: SettingsMenuProps) { const { state, set: setSettingsState } = useSettingsState(); const layoutContext = useMaybeLayoutContext(); const room = useRoomContext(); const recordingEndpoint = process.env.NEXT_PUBLIC_LK_RECORD_ENDPOINT; const settings = React.useMemo(() => { return { media: { camera: true, microphone: true, label: 'Media Devices', speaker: true }, recording: recordingEndpoint ? { label: 'Recording' } : undefined, keyboard: { label: 'Keybindings', keybindings: keybindingOptions, }, } as const; }, []); const tabs = React.useMemo( () => Object.keys(settings).filter((t) => t !== undefined) as Array, [settings], ); const [activeTab, setActiveTab] = React.useState(tabs[0]); const isRecording = useIsRecording(); const [initialRecStatus, setInitialRecStatus] = React.useState(isRecording); const [processingRecRequest, setProcessingRecRequest] = React.useState(false); React.useEffect(() => { if (initialRecStatus !== isRecording) { setProcessingRecRequest(false); } }, [isRecording, initialRecStatus]); const toggleRoomRecording = async () => { if (!recordingEndpoint) { throw TypeError('No recording endpoint specified'); } if (room.isE2EEEnabled) { throw Error('Recording of encrypted meetings is currently not supported'); } setProcessingRecRequest(true); setInitialRecStatus(isRecording); let response: Response; if (isRecording) { response = await fetch(recordingEndpoint + `/stop?roomName=${room.name}`); } else { response = await fetch(recordingEndpoint + `/start?roomName=${room.name}`); } if (response.ok) { } else { console.error( 'Error handling recording request, check server logs:', response.status, response.statusText, ); setProcessingRecRequest(false); } }; const setKeyBinding = (key: KeyCommand, binds: KeyBinding | [KeyBinding, KeyBinding]) => { setSettingsState((prev) => ({ ...prev, keybindings: { ...prev.keybindings, [key]: binds, }, })); }; return (
{tabs.map( (tab) => settings[tab] && ( ), )}
{activeTab === 'media' && ( <> {settings.media && settings.media.camera && ( <>

Camera

)} {settings.media && settings.media.microphone && ( <>

Microphone

)} {settings.media && settings.media.speaker && ( <>

Speaker & Headphones

Audio Output
)} )} {activeTab === 'recording' && ( <>

Record Meeting

{isRecording ? 'Meeting is currently being recorded' : 'No active recordings for this meeting'}

)} {activeTab === 'keyboard' && ( <>

PTT

PTT trigger

{settings.keyboard.keybindings[KeyCommand.PTT]?.map(({ label, binds }) => (
setKeyBinding(KeyCommand.PTT, binds)} />
))}
)}
); }