import { useSyncExternalStore, useRef } from 'react'; import { useAviationPlayer } from '../AviationContext'; import type { CastState, CastDevice } from '../specs/types.nitro'; import type { AviationPlayer } from '../Aviation'; export interface CastStateInfo { /** Current cast connection state. */ state: CastState; /** Connected device info, if any. */ device: CastDevice | undefined; /** Whether audio/video is being sent to an external device. */ isConnected: boolean; } const IDLE_CAST_STATE: CastStateInfo = { state: 'disconnected', device: undefined, isConnected: false, }; /** * Subscribe to AirPlay/cast connection state changes. * * Reflects whichever playback output currently owns the session: AirPlay * presence on iOS, a Cast session on either platform (Chromecast requires * @react-native-aviation/cast). * * Uses a ref-memoized snapshot so identical state does not trigger re-renders. * * @example * ```tsx * const { isConnected, device } = useCastState(); * if (isConnected) { * console.log(`Playing on ${device?.name}`); * } * ``` */ export function useCastState(playerArg?: AviationPlayer): CastStateInfo { const player = useAviationPlayer(playerArg); const store = player.store; const ref = useRef(IDLE_CAST_STATE); const getSnapshot = () => { const snapshot = store.getCastStateSnapshot(); const prev = ref.current; if ( prev.state === snapshot.state && prev.device === snapshot.device && prev.isConnected === snapshot.isConnected ) { return prev; } ref.current = { state: snapshot.state, device: snapshot.device, isConnected: snapshot.isConnected, }; return ref.current; }; return useSyncExternalStore(store.subscribeCastState, getSnapshot); }