import { Subject } from 'rxjs'; import { ChatEvent } from '../../../shared-kernel'; import { WebRTCLogger } from '../logging/webrtc-logger'; import { DisconnectedPeerEntry, IdentifyCredentials, PeerData, VoiceStateSnapshot } from '../realtime.types'; /** * Callbacks the PeerConnectionManager needs from the owning service. * This keeps the manager decoupled from Angular DI / signals. */ export interface PeerConnectionCallbacks { /** Send a raw JSON message via the signaling server. */ sendRawMessage(msg: Record): void; /** Get the current local media stream (mic audio). */ getLocalMediaStream(): MediaStream | null; /** Whether signaling is currently connected. */ isSignalingConnected(): boolean; /** Returns the current voice/screen state snapshot for broadcasting. */ getVoiceStateSnapshot(): VoiceStateSnapshot; /** Returns the identify credentials (oderId + displayName). */ getIdentifyCredentials(): IdentifyCredentials | null; /** Returns the local peer ID. */ getLocalPeerId(): string; /** Whether screen sharing is active. */ isScreenSharingActive(): boolean; /** Whether the local camera is active. */ isCameraEnabled(): boolean; } export interface PeerConnectionManagerState { activePeerConnections: Map; remotePeerStreams: Map; remotePeerVoiceStreams: Map; remotePeerCameraStreams: Map; remotePeerScreenShareStreams: Map; disconnectedPeerTracker: Map; peerReconnectTimers: Map>; peerDisconnectGraceTimers: Map>; pendingPings: Map; peerPingTimers: Map>; peerLatencies: Map; peerLatencyChanged$: Subject<{ peerId: string; latencyMs: number }>; peerNegotiationQueue: Map>; peerConnected$: Subject; peerDisconnected$: Subject; remoteStream$: Subject<{ peerId: string; stream: MediaStream }>; messageReceived$: Subject; connectedPeersChanged$: Subject; connectedPeersList: string[]; } export interface PeerConnectionManagerContext { readonly logger: WebRTCLogger; readonly callbacks: PeerConnectionCallbacks; readonly state: PeerConnectionManagerState; } export interface RemovePeerOptions { preserveReconnectState?: boolean; } export interface ConnectionLifecycleHandlers { clearPeerDisconnectGraceTimer(peerId: string): void; addToConnectedPeers(peerId: string): void; clearPeerReconnectTimer(peerId: string): void; requestVoiceStateFromPeer(peerId: string): void; schedulePeerDisconnectRecovery(peerId: string): void; trackDisconnectedPeer(peerId: string): void; removePeer(peerId: string, options?: RemovePeerOptions): void; schedulePeerReconnect(peerId: string): void; handleRemoteTrack(event: RTCTrackEvent, remotePeerId: string): void; setupDataChannel(channel: RTCDataChannel, remotePeerId: string): void; } export interface NegotiationHandlers { createPeerConnection(remotePeerId: string, isInitiator: boolean): PeerData; } export interface RecoveryHandlers { removePeer(peerId: string, options?: RemovePeerOptions): void; createPeerConnection(peerId: string, isInitiator: boolean): PeerData; createAndSendOffer(peerId: string): Promise; } export function createPeerConnectionManagerState(): PeerConnectionManagerState { return { activePeerConnections: new Map(), remotePeerStreams: new Map(), remotePeerVoiceStreams: new Map(), remotePeerCameraStreams: new Map(), remotePeerScreenShareStreams: new Map(), disconnectedPeerTracker: new Map(), peerReconnectTimers: new Map>(), peerDisconnectGraceTimers: new Map>(), pendingPings: new Map(), peerPingTimers: new Map>(), peerLatencies: new Map(), peerLatencyChanged$: new Subject<{ peerId: string; latencyMs: number }>(), peerNegotiationQueue: new Map>(), peerConnected$: new Subject(), peerDisconnected$: new Subject(), remoteStream$: new Subject<{ peerId: string; stream: MediaStream }>(), messageReceived$: new Subject(), connectedPeersChanged$: new Subject(), connectedPeersList: [] }; }