import { useEffect, useMemo, useState } from 'react'; import { SettingsProvider } from '../settings/index.js'; import { useSession } from '../context/SessionContext.jsx'; import { useTelemetryFrames } from '../context/TelemetryContext.jsx'; import { useVideoRequests } from '../hooks/useVideoRequests.js'; import { useRoverSnapshots } from '../hooks/useRoverSnapshots.js'; import { useSpectatorMode } from '../hooks/useSpectatorMode.js'; import { useRoomCameraSnapshots } from '../hooks/useRoomCameraSnapshots.js'; import VideoTile from '../components/VideoTile.jsx'; import ChatPanel from '../components/ChatPanel.jsx'; import AlertFeed from '../components/AlertFeed.jsx'; import useDefaultNickname from '../hooks/useDefaultNickname.js'; import RoomCameraFeed from '../components/RoomCameraFeed.jsx'; import { supportsAv1WebRtc } from '../lib/mediaSupport.js'; const ROTATE_MS = 20000; function formatDriverLabel({ roverId, session }) { const activeDriverId = session?.activeDrivers?.[roverId] || null; const user = (session?.users || []).find((entry) => entry.socketId === activeDriverId); const label = user?.nickname || (activeDriverId ? activeDriverId.slice(0, 6) : 'No driver'); const mode = session?.mode; const turnInfo = session?.turnQueues?.[roverId]; return mode === 'turns' && turnInfo?.current ? `${label} (turns)` : label; } function MiniSummaryContent() { const { session } = useSession(); const spectatorReady = useSpectatorMode(); useDefaultNickname(); const inLockdown = session?.mode === 'lockdown'; const frames = useTelemetryFrames(); const roster = session?.roster ?? []; const roomCameras = session?.roomCameras || []; const feeds = useRoomCameraSnapshots(roomCameras.map((camera) => ({ id: camera.id })), { enabled: !inLockdown, version: session?.mode, }); const [index, setIndex] = useState(0); const snapshotFeeds = useRoverSnapshots( roster.map((rover) => rover.id), { enabled: !inLockdown, version: session?.mode }, ); const av1Supported = supportsAv1WebRtc(); const previewEntries = roster.map((rover) => ({ type: 'rover', id: rover.id, key: `rover:${rover.id}:preview:av1`, preview: true, codec: 'av1', })); const roomPreviewEntries = roomCameras.map((camera) => ({ type: 'room', id: camera.id, key: `room:${camera.id}:preview:av1`, preview: true, codec: 'av1', })); const previewSources = useVideoRequests(previewEntries, { enabled: !inLockdown && av1Supported }); const roomPreviewSources = useVideoRequests(roomPreviewEntries, { enabled: !inLockdown && av1Supported }); const audioEntries = useMemo( () => roster.flatMap((rover) => { if (!rover?.id || !rover.media?.audioPublishUrl) return []; const id = String(rover.id); return [{ type: 'rover', id: `${id}-audio`, key: `${id}-audio` }]; }), [roster], ); const audioSources = useVideoRequests(audioEntries, { enabled: !inLockdown, version: session?.mode }); const roverPool = useMemo(() => { if (!roster.length) return []; const withSnapshot = roster.filter((rover) => snapshotFeeds[rover.id]?.objectUrl); return withSnapshot.length ? withSnapshot : roster; }, [roster, snapshotFeeds]); const rotationPool = useMemo(() => { const items = []; roverPool.forEach((rover) => items.push({ type: 'rover', rover })); roomCameras.forEach((camera) => items.push({ type: 'room', camera })); return items; }, [roverPool, roomCameras]); const rotationKey = useMemo( () => rotationPool .map((entry) => entry.type === 'rover' ? `r:${entry.rover.id}` : `room:${entry.camera.id}`, ) .join('|'), [rotationPool], ); useEffect(() => { setIndex(0); }, [rotationKey]); useEffect(() => { if (!rotationPool.length) return undefined; const timer = setInterval(() => { setIndex((prev) => (prev + 1) % rotationPool.length); }, ROTATE_MS); return () => clearInterval(timer); }, [rotationPool.length, rotationKey]); const activeEntry = rotationPool.length ? rotationPool[index % rotationPool.length] : null; const activeRover = activeEntry?.type === 'rover' ? activeEntry.rover : null; const activeCamera = activeEntry?.type === 'room' ? activeEntry.camera : null; const activeSnapshot = activeRover ? snapshotFeeds[activeRover.id] || null : null; const activePreview = activeRover && previewSources[`rover:${activeRover.id}:preview:av1`] ? previewSources[`rover:${activeRover.id}:preview:av1`] : null; const activeAudio = activeRover ? audioSources[`${activeRover.id}-audio`] || null : null; const activeFrame = activeRover ? frames[activeRover.id] || null : null; const driverLabel = activeRover ? formatDriverLabel({ roverId: activeRover.id, session }) : null; const activeFeed = activeCamera ? feeds[activeCamera.id] || null : null; const activeRoomPreview = activeCamera && roomPreviewSources[`room:${activeCamera.id}:preview:av1`] ? roomPreviewSources[`room:${activeCamera.id}:preview:av1`] : null; if (inLockdown) { return (

Mini spectator is disabled in lockdown.

It will automatically resume once lockdown ends.

); } return (
{!spectatorReady ? (
Switching to spectator…
) : activeRover ? ( ) : activeCamera ? ( ) : (
No sources available.
)}
); } export default function MiniSummaryApp() { return ( <> ); } function RoomCameraFrame({ camera, feed, videoSession, preferVideo }) { return (
); } function ChatOverlay() { return (
); } function FitViewportFrame({ children }) { return (
{children}
); }