2 Commits

Author SHA1 Message Date
9ea57cd659 v1.20.5
Some checks failed
Docker (tags) / release (push) Failing after 3s
2026-04-11 19:20:14 +00:00
c40c726dc3 fix(readme): improve architecture and call flow documentation with Mermaid diagrams 2026-04-11 19:20:14 +00:00
5 changed files with 71 additions and 39 deletions

View File

@@ -1,5 +1,11 @@
# 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)
bump @design.estate/dees-catalog to ^3.71.1

View File

@@ -1,6 +1,6 @@
{
"name": "siprouter",
"version": "1.20.4",
"version": "1.20.5",
"private": true,
"type": "module",
"scripts": {

View File

@@ -28,39 +28,26 @@ siprouter sits between your SIP trunk providers and your endpoints — hardware
## 🏗️ Architecture
```
┌─────────────────────────────────────┐
Browser Softphone
(WebRTC via WebSocket signaling) │
└──────────────┬──────────────────────┘
│ Opus/WebRTC
┌──────────────────────────────────────┐
siprouter │
TypeScript Control Plane │
│ ┌────────────────────────────────┐ │
│ │ Config · WebRTC Signaling │ │
│ REST API · Web Dashboard │ │
│ Voicebox Manager · TTS Cache │ │
└────────────┬───────────────────┘ │
│ JSON-over-stdio IPC │
┌────────────┴───────────────────┐ │
Rust proxy-engine (data plane) │ │
│ │
│ │ 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 │
└─────────────┘ └─────────────┘
```mermaid
flowchart TB
Browser["🌐 Browser Softphone<br/>(WebRTC via WebSocket signaling)"]
Devices["📞 SIP Devices<br/>(HT801, desk phones, ATAs)"]
Trunks["☎️ SIP Trunk Providers<br/>(sipgate, easybell, …)"]
subgraph Router["siprouter"]
direction TB
subgraph TS["TypeScript Control Plane"]
TSBits["Config · WebRTC Signaling<br/>REST API · Web Dashboard<br/>Voicebox Manager · TTS Cache"]
end
subgraph Rust["Rust proxy-engine (data plane)"]
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"]
end
TS <-->|"JSON-over-stdio IPC"| Rust
end
Browser <-->|"Opus / WebRTC"| TS
Rust <-->|"SIP / RTP"| Devices
Rust <-->|"SIP / RTP"| Trunks
```
### 🧠 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.
- **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
@@ -246,9 +264,17 @@ The `proxy-engine` binary handles all real-time audio processing with a **48kHz
### Audio Pipeline
```
Inbound: Wire RTP → Jitter Buffer → Decode → Resample to 48kHz → Denoise (RNNoise) → Mix Bus
Outbound: Mix Bus → Mix-Minus → Resample to codec rate → Encode → Wire RTP
```mermaid
flowchart LR
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 26 frames based on observed network jitter. Handles hold/resume by detecting large forward sequence jumps and resetting cleanly.

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: 'siprouter',
version: '1.20.4',
version: '1.20.5',
description: 'undefined'
}

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: 'siprouter',
version: '1.20.4',
version: '1.20.5',
description: 'undefined'
}