Architecture¶
End-to-end call flow¶
sequenceDiagram
participant User as SIP handset
participant PBX as Your PBX
participant Ex as sip-dmr-exchange
participant Br as sip-dmr-bridge
participant DMR as DMR / SystemX server
User->>PBX: Dial feature code + enter TG
PBX->>Ex: INVITE PJSIP/TG@sip-dmr-exchange + headers
Ex->>Br: Docker spawn + SIP B2BUA
Br->>DMR: MMDVM login
Ex-->>PBX: 200 OK after bridge healthy
User<<->>DMR: Audio via exchange
Components¶
| Layer | Typical host | Responsibility |
|---|---|---|
| IVR + access | PBX | Feature code, talkgroup entry, allowlist |
| SIP trunk | PBX | PJSIP/${TG}@sip-dmr-exchange |
| Exchange | Portal VM | Auth, provision bridge, B2BUA media |
| Bridge | Portal VM (Docker) | One container per call; MMDVM client |
| Dashboard | Portal VM (optional) | Static UI + nginx proxy to HTTP API |
SIP headers (PBX → exchange)¶
| Header | Purpose |
|---|---|
X-Auth-Token |
Shared secret; exchange returns 403 if missing/wrong |
X-Callsign |
Caller callsign for bridge naming and RadioId lookup |
X-DMR-Id |
Optional explicit DMR ID |
X-DMR-SSID |
Optional SSID suffix for SystemX client ID |
Talkgroup is the SIP request URI user part (the ${TG} in PJSIP/${TG}@trunk).
Exchange internals¶
- Listens on
SIP_BIND_ADDR:SIP_BIND_PORT(default0.0.0.0:5060) - On INVITE: provisions
sip-dmr-bridge:latestvia local Docker socket - Holds call until bridge HEALTHCHECK passes (~5–15 s cold start)
- Bridges RTP between incoming PBX leg and bridge leg (B2BUA)
- Enforces
MAX_ACTIVE_CALLS— returns SIP 503 when at capacity
HTTP API¶
Optional nginx (or similar) can expose:
GET /bridges¶
Active bridge sessions (no auth on read in current implementation):
[{
"callsign": "M0ABC",
"dmr_id": 1234567,
"talkgroup": 234,
"state": "Active",
"state_time": "2026-08-16T12:00:00",
"active": true
}]
Bridge states: Inactive, Provisioning, Provisioned, Active, Deprovisioning, Deprovisioned.
GET /stats¶
Per-call resource cost¶
Measured on a small portal VM:
- ~130–150 MB RAM per bridge container (includes
md380-emu) - ~10–15% CPU per active bridge under TX/RX
- ~5–15 s until bridge healthy (caller may hear ringing)
Size your VM accordingly; see Scaling.
Related¶
Last update: August 17, 2026 21:08:54
Last updated by: MØVUB
Last updated by: MØVUB
Help improve this page by contributing to our documentation.