Skip to content
File

Blob: worker/src/client/radio/use-radio.ts

typescript31 lines
1import { useEffect, useRef, useState, useSyncExternalStore } from 'react';
2import type { Command } from '@/shared/contracts/robot.ts';
3import { RadioSession } from './session.ts';
4 
5/** The React boundary owns one session and exposes bound actions to the exhibit. */
6export function useRadio() {
7 const [{ session, actions }] = useState(() => {
8 const session = new RadioSession();
9 return {
10 session,
11 actions: {
12 login: (password: string) => session.login(password),
13 connect: () => session.connect(),
14 disconnect: () => session.disconnect(),
15 toggleAudio: () => session.toggleAudio(),
16 setVolume: (volume: number) => session.setVolume(volume),
17 toggleControl: () => session.toggleControl(),
18 send: (command: Command) => session.send(command),
19 },
20 };
21 });
22 const audioRef = useRef<HTMLAudioElement>(null);
23 const state = useSyncExternalStore(session.subscribe, session.getSnapshot);
24 useEffect(() => {
25 if (audioRef.current) return session.start(audioRef.current);
26 }, [session]);
27 return { state, signal: session.signal, actions, audioRef };
28}
29 
30export type RadioActions = ReturnType<typeof useRadio>['actions'];