fix(readme): improve architecture and call flow documentation with Mermaid diagrams
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-04-11 - 1.20.5 - fix(readme)
|
||||||
|
improve architecture and call flow documentation with Mermaid diagrams
|
||||||
|
|
||||||
|
- Replace ASCII architecture and audio pipeline diagrams with Mermaid diagrams for better readability
|
||||||
|
- Document the WebRTC browser call setup sequence, including offer handling and session-to-call linking
|
||||||
|
|
||||||
## 2026-04-11 - 1.20.4 - fix(deps)
|
## 2026-04-11 - 1.20.4 - fix(deps)
|
||||||
bump @design.estate/dees-catalog to ^3.71.1
|
bump @design.estate/dees-catalog to ^3.71.1
|
||||||
|
|
||||||
|
|||||||
98
readme.md
98
readme.md
@@ -28,39 +28,26 @@ siprouter sits between your SIP trunk providers and your endpoints — hardware
|
|||||||
|
|
||||||
## 🏗️ Architecture
|
## 🏗️ Architecture
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
┌─────────────────────────────────────┐
|
flowchart TB
|
||||||
│ Browser Softphone │
|
Browser["🌐 Browser Softphone<br/>(WebRTC via WebSocket signaling)"]
|
||||||
│ (WebRTC via WebSocket signaling) │
|
Devices["📞 SIP Devices<br/>(HT801, desk phones, ATAs)"]
|
||||||
└──────────────┬──────────────────────┘
|
Trunks["☎️ SIP Trunk Providers<br/>(sipgate, easybell, …)"]
|
||||||
│ Opus/WebRTC
|
|
||||||
▼
|
subgraph Router["siprouter"]
|
||||||
┌──────────────────────────────────────┐
|
direction TB
|
||||||
│ siprouter │
|
subgraph TS["TypeScript Control Plane"]
|
||||||
│ │
|
TSBits["Config · WebRTC Signaling<br/>REST API · Web Dashboard<br/>Voicebox Manager · TTS Cache"]
|
||||||
│ TypeScript Control Plane │
|
end
|
||||||
│ ┌────────────────────────────────┐ │
|
subgraph Rust["Rust proxy-engine (data plane)"]
|
||||||
│ │ Config · WebRTC Signaling │ │
|
RustBits["SIP Stack · Dialog SM · Auth<br/>Call Manager · N-Leg Mixer<br/>48kHz f32 Bus · Jitter Buffer<br/>Codec Engine · RTP Port Pool<br/>WebRTC Engine · Kokoro TTS<br/>Voicemail · IVR · Recording"]
|
||||||
│ │ REST API · Web Dashboard │ │
|
end
|
||||||
│ │ Voicebox Manager · TTS Cache │ │
|
TS <-->|"JSON-over-stdio IPC"| Rust
|
||||||
│ └────────────┬───────────────────┘ │
|
end
|
||||||
│ JSON-over-stdio IPC │
|
|
||||||
│ ┌────────────┴───────────────────┐ │
|
Browser <-->|"Opus / WebRTC"| TS
|
||||||
│ │ Rust proxy-engine (data plane) │ │
|
Rust <-->|"SIP / RTP"| Devices
|
||||||
│ │ │ │
|
Rust <-->|"SIP / RTP"| Trunks
|
||||||
│ │ SIP Stack · Dialog SM · Auth │ │
|
|
||||||
│ │ Call Manager · N-Leg Mixer │ │
|
|
||||||
│ │ 48kHz f32 Bus · Jitter Buffer │ │
|
|
||||||
│ │ Codec Engine · RTP Port Pool │ │
|
|
||||||
│ │ WebRTC Engine · Kokoro TTS │ │
|
|
||||||
│ │ Voicemail · IVR · Recording │ │
|
|
||||||
│ └────┬──────────────────┬────────┘ │
|
|
||||||
└───────┤──────────────────┤───────────┘
|
|
||||||
│ │
|
|
||||||
┌──────┴──────┐ ┌──────┴──────┐
|
|
||||||
│ SIP Devices │ │ SIP Trunk │
|
|
||||||
│ (HT801 etc) │ │ Providers │
|
|
||||||
└─────────────┘ └─────────────┘
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 🧠 Key Design Decisions
|
### 🧠 Key Design Decisions
|
||||||
@@ -71,6 +58,37 @@ siprouter sits between your SIP trunk providers and your endpoints — hardware
|
|||||||
- **Per-Session Codec Isolation** — Each call leg gets its own encoder/decoder/resampler/denoiser state — no cross-call corruption.
|
- **Per-Session Codec Isolation** — Each call leg gets its own encoder/decoder/resampler/denoiser state — no cross-call corruption.
|
||||||
- **SDP Codec Negotiation** — Outbound encoding uses the codec actually negotiated in SDP answers, not just the first offered codec.
|
- **SDP Codec Negotiation** — Outbound encoding uses the codec actually negotiated in SDP answers, not just the first offered codec.
|
||||||
|
|
||||||
|
### 📲 WebRTC Browser Call Flow
|
||||||
|
|
||||||
|
Browser calls are set up in a strict three-step dance — the WebRTC leg cannot be attached at call-creation time because the browser's session ID is only known once the SDP offer arrives:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
sequenceDiagram
|
||||||
|
participant B as Browser
|
||||||
|
participant TS as TypeScript (sipproxy.ts)
|
||||||
|
participant R as Rust proxy-engine
|
||||||
|
participant P as SIP Provider
|
||||||
|
|
||||||
|
B->>TS: POST /api/call
|
||||||
|
TS->>R: make_call (pending call, no WebRTC leg yet)
|
||||||
|
R-->>TS: call_created
|
||||||
|
TS-->>B: webrtc-incoming (callId)
|
||||||
|
|
||||||
|
B->>TS: webrtc-offer (sessionId, SDP)
|
||||||
|
TS->>R: handle_webrtc_offer
|
||||||
|
R-->>TS: webrtc-answer (SDP)
|
||||||
|
TS-->>B: webrtc-answer
|
||||||
|
Note over R: Standalone WebRTC session<br/>(not yet attached to call)
|
||||||
|
|
||||||
|
B->>TS: webrtc_link (callId + sessionId)
|
||||||
|
TS->>R: link session → call
|
||||||
|
R->>R: wire WebRTC leg through mixer
|
||||||
|
R->>P: SIP INVITE
|
||||||
|
P-->>R: 200 OK + SDP
|
||||||
|
R-->>TS: call_answered
|
||||||
|
Note over B,P: Bidirectional Opus ↔ codec-transcoded<br/>audio flows through the mixer
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Getting Started
|
## 🚀 Getting Started
|
||||||
@@ -246,9 +264,17 @@ The `proxy-engine` binary handles all real-time audio processing with a **48kHz
|
|||||||
|
|
||||||
### Audio Pipeline
|
### Audio Pipeline
|
||||||
|
|
||||||
```
|
```mermaid
|
||||||
Inbound: Wire RTP → Jitter Buffer → Decode → Resample to 48kHz → Denoise (RNNoise) → Mix Bus
|
flowchart LR
|
||||||
Outbound: Mix Bus → Mix-Minus → Resample to codec rate → Encode → Wire RTP
|
subgraph Inbound["Inbound path (per leg)"]
|
||||||
|
direction LR
|
||||||
|
IN_RTP["Wire RTP"] --> IN_JB["Jitter Buffer"] --> IN_DEC["Decode"] --> IN_RS["Resample → 48 kHz"] --> IN_DN["Denoise (RNNoise)"] --> IN_BUS["Mix Bus"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph Outbound["Outbound path (per leg)"]
|
||||||
|
direction LR
|
||||||
|
OUT_BUS["Mix Bus"] --> OUT_MM["Mix-Minus"] --> OUT_RS["Resample → codec rate"] --> OUT_ENC["Encode"] --> OUT_RTP["Wire RTP"]
|
||||||
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
- **Adaptive jitter buffer** — per-leg `BTreeMap`-based buffer keyed by RTP sequence number. Delivers exactly one frame per 20ms mixer tick in sequence order. Adaptive target depth starts at 3 frames (60ms) and adjusts between 2–6 frames based on observed network jitter. Handles hold/resume by detecting large forward sequence jumps and resetting cleanly.
|
- **Adaptive jitter buffer** — per-leg `BTreeMap`-based buffer keyed by RTP sequence number. Delivers exactly one frame per 20ms mixer tick in sequence order. Adaptive target depth starts at 3 frames (60ms) and adjusts between 2–6 frames based on observed network jitter. Handles hold/resume by detecting large forward sequence jumps and resetting cleanly.
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: 'siprouter',
|
name: 'siprouter',
|
||||||
version: '1.20.4',
|
version: '1.20.5',
|
||||||
description: 'undefined'
|
description: 'undefined'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: 'siprouter',
|
name: 'siprouter',
|
||||||
version: '1.20.4',
|
version: '1.20.5',
|
||||||
description: 'undefined'
|
description: 'undefined'
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user