export interface IProviderMediaInfo { addr: string; port: number; sipPt: number; } export interface IWebRtcLinkTarget { sessionId: string; media: IProviderMediaInfo; } export class WebRtcLinkManager { private sessionToCall = new Map(); private callToSession = new Map(); private pendingCallMedia = new Map(); acceptCall(callId: string, sessionId: string): IProviderMediaInfo | null { const previousCallId = this.sessionToCall.get(sessionId); if (previousCallId && previousCallId !== callId) { this.callToSession.delete(previousCallId); } const previousSessionId = this.callToSession.get(callId); if (previousSessionId && previousSessionId !== sessionId) { this.sessionToCall.delete(previousSessionId); } this.sessionToCall.set(sessionId, callId); this.callToSession.set(callId, sessionId); const pendingMedia = this.pendingCallMedia.get(callId) ?? null; if (pendingMedia) { this.pendingCallMedia.delete(callId); } return pendingMedia; } noteCallAnswered(callId: string, media: IProviderMediaInfo): IWebRtcLinkTarget | null { const sessionId = this.callToSession.get(callId); if (!sessionId) { this.pendingCallMedia.set(callId, media); return null; } return { sessionId, media }; } removeSession(sessionId: string): string | null { const callId = this.sessionToCall.get(sessionId) ?? null; this.sessionToCall.delete(sessionId); if (callId) { this.callToSession.delete(callId); } return callId; } cleanupCall(callId: string): string | null { const sessionId = this.callToSession.get(callId) ?? null; this.callToSession.delete(callId); this.pendingCallMedia.delete(callId); if (sessionId) { this.sessionToCall.delete(sessionId); } return sessionId; } }