# Project Notes ## Architecture: Hub Model (Call as Centerpiece) All call logic lives in `ts/call/`. The Call is the central entity with N legs. ### Key Files - `ts/call/call-manager.ts` — singleton registry, factory methods, SIP routing - `ts/call/call.ts` — the hub: owns legs, media forwarding - `ts/call/sip-leg.ts` — SIP device/provider connection (wraps SipDialog) - `ts/call/webrtc-leg.ts` — browser WebRTC connection (wraps werift PeerConnection) - `ts/call/rtp-port-pool.ts` — unified RTP port pool - `ts/sipproxy.ts` — thin bootstrap wiring everything together - `ts/webrtcbridge.ts` — browser device registration (signaling only) ### WebRTC Browser Call Flow (Critical) The browser call flow has a specific signaling order that MUST be followed: 1. `POST /api/call` with browser deviceId → CallManager creates Call, saves pending state, notifies browser via `webrtc-incoming` 2. Browser sends `webrtc-offer` (with its own `sessionId`) → CallManager creates a **standalone** WebRtcLeg (NOT attached to any call yet) 3. Browser sends `webrtc-accept` (with `callId` + `sessionId`) → CallManager links the standalone WebRtcLeg to the Call, then starts the SIP provider leg **The WebRtcLeg CANNOT be created at call creation time** because the browser's session ID is unknown until the `webrtc-offer` arrives. ### WebRTC Audio Return Channel (Critical) The SIP→browser audio path works through the Call hub: 1. Provider sends RTP to SipLeg's socket 2. SipLeg's `onRtpReceived` fires → Call hub's `forwardRtp` 3. Call hub calls `webrtcLeg.sendRtp(data)` → which calls `forwardToBrowser()` 4. `forwardToBrowser` transcodes (G.722→Opus) and sends via `sender.sendRtp()` (WebRTC PeerConnection) **`WebRtcLeg.sendRtp()` MUST feed into `forwardToBrowser()`** (the WebRTC PeerConnection path), NOT send to a UDP address. This was a bug that caused one-way audio. The browser→SIP direction works independently: `ontrack.onReceiveRtp` → `forwardToSip()` → transcodes → sends directly to provider's media endpoint via UDP. ### SIP Protocol Library `ts/sip/` is a zero-dependency SIP protocol library. Do not add transport or timer logic there — it's purely data-level (parse/build/mutate/serialize).