/** * Which external output is present, resolved from independent sources. * * An AirPlay route (audible elsewhere, local engine still plays) and an * owning session (e.g. Cast) each publish only their own contribution here; * this module decides what the store sees. A session wins over a route. */ import type { AviationStore } from '../store'; import type { CastDevice } from '../specs/types.nitro'; export interface OutputPresence { /** AirPlay-style route: audible elsewhere, but the local engine still plays. */ setRoute(device: CastDevice | undefined): void; /** A session that owns playback, e.g. Cast. */ setSession(device: CastDevice | undefined): void; reset(): void; } export function createOutputPresence(store: AviationStore): OutputPresence { let route: CastDevice | undefined; let session: CastDevice | undefined; function publish(): void { const device = session ?? route; store.setCastState({ state: device ? 'connected' : 'disconnected', device, isConnected: device !== undefined, }); } return { setRoute(device): void { if (route === device) return; route = device; publish(); }, setSession(device): void { if (session === device) return; session = device; publish(); }, reset(): void { route = undefined; session = undefined; publish(); }, }; }