export type RemoteProtocol = 'sfu' | 'p2p' | 'mcu'; /** Contrat unifié d'une souscription distante (cf. design §4.5). */ export interface RemoteSubscription { stream: MediaStream; protocol: RemoteProtocol; roomId: string; stop: () => Promise; } export interface UseRemoteSourceOptions { /** Protocole de la source distante. */ protocol: RemoteProtocol; /** Base de l'API du protocole. Ex SFU : `/api/sfu` ou `https://studio.amia.fr/api/sfu`. */ apiBase: string; /** Room / classroom à consommer. */ roomId: string; /** ICE servers (WebRTC). Défaut : STUN public. */ iceServers?: RTCIceServer[]; /** Si true, connecte automatiquement au montage. Défaut false (connect() explicite). */ autoConnect?: boolean; /** Si true, attend qu'un publisher soit actif (salle d'attente) au lieu * d'échouer. Poll l'état de la room et s'abonne dès qu'un publisher démarre. * Supporté SFU uniquement pour l'instant. */ waitForPublisher?: boolean; /** Intervalle de poll en ms quand `waitForPublisher`. Défaut 3000. */ pollIntervalMs?: number; } export type RemoteSourceStatus = 'idle' | 'waiting' | 'connecting' | 'connected' | 'error'; export interface UseRemoteSourceReturn { /** MediaStream live une fois connecté, sinon null. */ stream: MediaStream | null; /** idle → [waiting] → connecting → connected (ou error). */ status: RemoteSourceStatus; error: string | null; /** Établit la souscription (ou entre en salle d'attente si waitForPublisher). */ connect: () => Promise; /** Ferme la souscription + arrête le poll + libère les ressources. */ disconnect: () => Promise; } /** * S'abonne à un flux distant. Le `stream` retourné s'utilise comme n'importe * quelle source — `