Full-featured SIP router with multi-provider trunking, browser softphone via WebRTC, real-time Opus/G.722/PCM transcoding in Rust, RNNoise ML noise suppression, Kokoro neural TTS announcements, and a Lit-based web dashboard with live call monitoring and REST API.
@serve.zone/siprouter
A production-grade SIP B2BUA + WebRTC bridge built with TypeScript and Rust. Routes calls between SIP providers, SIP hardware devices, and browser softphones — with real-time codec transcoding, ML noise suppression, neural TTS announcements, and a slick web dashboard.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
🔥 What It Does
siprouter sits between your SIP trunk providers and your endpoints — hardware phones, ATAs, browser softphones — and handles everything in between:
- 📞 SIP B2BUA — Terminates and re-originates calls with full RFC 3261 dialog state management
- 🌐 WebRTC Bridge — Browser-based softphone with bidirectional audio to the SIP network
- 🎛️ Multi-Provider Trunking — Register with multiple SIP providers simultaneously (sipgate, easybell, o2, etc.)
- 🔊 Rust Codec Engine — Real-time Opus ↔ G.722 ↔ PCMU ↔ PCMA transcoding in native Rust
- 🤖 ML Noise Suppression — RNNoise denoiser with per-direction state (to SIP / to browser)
- 🗣️ Neural TTS — Kokoro-powered "connecting your call" announcements, pre-encoded for instant playback
- 🔀 Hub Model Calls — N-leg calls with dynamic add/remove, transfer, and RTP fan-out
- 🖥️ Web Dashboard — Real-time SPA with live call monitoring, browser phone, contact management, provider config
🏗️ Architecture
┌─────────────────────────────────────┐
│ Browser Softphone │
│ (WebRTC via WebSocket signaling) │
└──────────────┬──────────────────────┘
│ Opus/WebRTC
▼
┌──────────────────────────────────────┐
│ siprouter │
│ │
│ ┌──────────┐ ┌──────────────────┐ │
│ │ Call Hub │ │ Rust Transcoder │ │
│ │ N legs │──│ Opus/G.722/PCM │ │
│ │ fan-out │ │ + RNNoise │ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
│ ┌────┴─────┐ ┌──────────────────┐ │
│ │ SIP Stack│ │ Kokoro TTS │ │
│ │ Dialog SM│ │ (ONNX Runtime) │ │
│ └────┬─────┘ └──────────────────┘ │
│ │ │
│ ┌────┴──────────────────────────┐ │
│ │ Local Registrar + Provider │ │
│ │ Registration Engine │ │
│ └───────────────────────────────┘ │
└──────────┬──────────────┬────────────┘
│ │
┌──────┴──────┐ ┌─────┴──────┐
│ SIP Devices │ │ SIP Trunk │
│ (HT801, etc)│ │ Providers │
└─────────────┘ └────────────┘
The Hub Model
Every call is a hub with N legs. Each leg is either a SipLeg (hardware device or provider) or a WebRtcLeg (browser). RTP flows through the hub — each leg's received audio is forwarded to all other legs, with codec transcoding handled transparently by the Rust engine.
🚀 Getting Started
Prerequisites
- Node.js ≥ 20 with
tsxglobally available - pnpm for package management
- Rust toolchain (for building the codec engine and TTS)
Install & Build
# Clone and install
pnpm install
# Build the Rust binaries (opus-codec + tts-engine)
pnpm run buildRust
# Bundle the web frontend
pnpm run bundle
Configuration
Create .nogit/config.json with your setup:
{
"proxy": {
"lanIp": "192.168.1.100", // Your server's LAN IP
"lanPort": 5070, // SIP signaling port
"rtpPortRange": [20000, 20200],// RTP relay port pool (even ports)
"webUiPort": 3060 // Dashboard port
},
"providers": [
{
"id": "my-trunk",
"name": "My SIP Provider",
"host": "sip.provider.com",
"port": 5060,
"username": "user",
"password": "pass",
"codecs": ["G.722", "PCMA", "PCMU"],
"registerExpiry": 3600
}
],
"devices": [
{
"id": "desk-phone",
"name": "Desk Phone",
"type": "sip"
}
],
"routing": {
"inbound": {
"default": { "target": "all-devices", "ringBrowser": true }
}
}
}
TTS Setup (Optional)
For neural "connecting your call" announcements, download the Kokoro TTS model:
mkdir -p .nogit/tts
# Download the full-quality model (310MB) + voices (27MB)
curl -L -o .nogit/tts/kokoro-v1.0.onnx \
https://github.com/mzdk100/kokoro/releases/download/V1.0/kokoro-v1.0.onnx
curl -L -o .nogit/tts/voices.bin \
https://github.com/mzdk100/kokoro/releases/download/V1.0/voices.bin
If the model files aren't present, the announcement feature is simply disabled — everything else works fine.
Run
pnpm start
The SIP proxy starts on the configured port and the web dashboard is available at http://<your-ip>:3060.
HTTPS (Optional)
Place cert.pem and key.pem in .nogit/ for TLS on the dashboard.
📂 Project Structure
siprouter/
├── ts/ # TypeScript source
│ ├── sipproxy.ts # Main entry — bootstraps everything
│ ├── config.ts # Config loader & validation
│ ├── registrar.ts # Local SIP registrar for devices
│ ├── providerstate.ts # Per-provider upstream registration engine
│ ├── frontend.ts # Web dashboard HTTP/WS server + REST API
│ ├── webrtcbridge.ts # WebRTC signaling layer
│ ├── opusbridge.ts # Rust IPC bridge (smartrust)
│ ├── codec.ts # High-level RTP transcoding interface
│ ├── announcement.ts # Neural TTS announcement generator
│ ├── sip/ # Zero-dependency SIP protocol library
│ │ ├── message.ts # SIP message parser/builder/mutator
│ │ ├── dialog.ts # RFC 3261 dialog state machine
│ │ ├── helpers.ts # SDP builder, digest auth, codec registry
│ │ └── rewrite.ts # SIP URI + SDP body rewriting
│ └── call/ # Hub-model call management
│ ├── call-manager.ts # Central registry, factory, routing
│ ├── call.ts # Call hub — owns N legs, media fan-out
│ ├── sip-leg.ts # SIP device/provider connection
│ ├── webrtc-leg.ts # Browser WebRTC connection
│ └── rtp-port-pool.ts # UDP port allocation
├── ts_web/ # Web frontend (Lit-based SPA)
│ ├── elements/ # Web components (dashboard, phone, etc.)
│ └── state/ # App state, WebRTC client, notifications
├── rust/ # Rust workspace
│ └── crates/
│ ├── opus-codec/ # Real-time audio transcoder (Opus/G.722/PCM)
│ └── tts-engine/ # Kokoro neural TTS CLI
├── html/ # Static HTML shell
├── .nogit/ # Secrets, config, models (gitignored)
└── dist_rust/ # Compiled Rust binaries (gitignored)
🎧 Codec Engine (Rust)
The opus-codec binary handles all real-time audio processing via a JSON-over-stdio IPC protocol:
| Codec | Payload Type | Sample Rate | Use Case |
|---|---|---|---|
| Opus | 111 | 48 kHz | WebRTC browsers |
| G.722 | 9 | 16 kHz | HD SIP devices |
| PCMU (G.711 µ-law) | 0 | 8 kHz | Legacy SIP |
| PCMA (G.711 A-law) | 8 | 8 kHz | Legacy SIP |
Features:
- Per-call isolated codec sessions (no cross-call state corruption)
- FFT-based sample rate conversion via
rubato - RNNoise ML noise suppression with per-direction state — denoises audio flowing to SIP separately from audio flowing to the browser
- Raw PCM encoding for TTS frame processing
🗣️ Neural TTS (Rust)
The tts-engine binary uses Kokoro TTS (82M parameter neural model) to synthesize announcements at startup:
- 24 kHz, 16-bit mono output
- 25+ voice presets — American/British, male/female (e.g.,
af_bella,am_adam,bf_emma,bm_george) - ~800ms synthesis time for a 3-second announcement
- Pre-encoded to G.722 + Opus for zero-latency RTP playback during call setup
🌐 Web Dashboard & REST API
Dashboard Views
| View | Description |
|---|---|
| Overview | Stats tiles — uptime, providers, devices, active calls |
| Calls | Active calls with leg details, codec info, packet counters. Add/remove legs, transfer, hangup |
| Phone | Browser softphone — mic/speaker selection, audio meters, dial pad, incoming call popup |
| Contacts | Contact management with click-to-call |
| Providers | SIP trunk config with registration status |
| Log | Live streaming log viewer |
REST API
| Endpoint | Method | Description |
|---|---|---|
/api/status |
GET | Full system status (providers, devices, calls) |
/api/call |
POST | Originate a call |
/api/hangup |
POST | Hang up a call |
/api/call/:id/addleg |
POST | Add a leg to an active call |
/api/call/:id/addexternal |
POST | Add an external participant |
/api/call/:id/removeleg |
POST | Remove a leg from a call |
/api/transfer |
POST | Transfer a call |
/api/config |
GET/POST | Read or update configuration (hot-reload) |
WebSocket Events
Connect to /ws for real-time push:
{ "type": "status", "data": { ... } } // Full status snapshot (1s interval)
{ "type": "log", "data": { "message": "..." } } // Log lines in real-time
🔌 Ports
| Port | Protocol | Purpose |
|---|---|---|
| 5070 (configurable) | UDP | SIP signaling |
| 20000–20200 (configurable) | UDP | RTP relay (even ports, per-call allocation) |
| 3060 (configurable) | TCP | Web dashboard + WebSocket + REST API |
🛠️ Development
# Start in dev mode
pnpm start
# Build Rust crates
pnpm run buildRust
# Bundle web frontend
pnpm run bundle
# Restart background server (build + bundle + restart)
pnpm run restartBackground
Key Design Decisions
- Hub Model — Calls are N-leg hubs, not point-to-point. This enables multi-party, dynamic leg manipulation, and transfer without tearing down the call.
- Zero-dependency SIP library —
ts/sip/is a pure data-level SIP stack (parse/build/mutate/serialize). No transport or timer logic — those live in the application layer. - Rust for the hot path — Codec transcoding and noise suppression run in native Rust for real-time performance. TypeScript handles signaling and orchestration.
- Per-session codec isolation — Each call gets its own Opus/G.722 encoder/decoder state in the Rust process, preventing stateful codec prediction from leaking between concurrent calls.
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the license file.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.