ADR-0173: Navin telephony platform: Asterisk, Kamailio, LiveKit SIP, SeaweedFS, multi-tenant and HA
- Status: accepted
- Date: 2026-11-03
- Scope: Navin Manager catalogue (
navin-manager/catalog/services/asterisk.yaml,kamailio.yaml,rtpengine.yaml,livekit*.yaml), telephony domain of the Control Plane (services/control-plane/src/eai/domains/telephony), migrationssql/postgres/V202__telephony*.sqland following, "Telephony" section of the portal (portal/src) - Related documents: ADR-0101 (licence policy), ADR-0166 (high availability declared per service), ADR-0171
(hardened installation), telephony guides (
docs/en/guides/telephony)
Context
The customer asks for a sellable enterprise telephony: PBX, SIP proxy, SIP gateway to LiveKit, voice AI agents,
multi-tenant, high availability, web interfaces, no demonstration. Two platforms exist and keep their role: the Navin
Manager and its agents install and run the infrastructure; Navin Enterprise AI Platform configures and administers the
uses. LiveKit Server is already in the catalogue (binary and podman methods, distributed mode on Redis) and the
Control Plane signs LiveKit room tokens for realtime voice; LiveKit SIP, LiveKit Egress, the agent workers, Asterisk,
Kamailio and RTPengine do not exist.
Decision
1. Two planes, explicit interfaces
| Who | Through what | Does what |
|---|---|---|
| Navin Manager | Navin agents on the hosts | installation, versions, system configuration, ports, certificates, clusters, HA, backups, health checks, rollback |
| Navin Enterprise | Asterisk AMI and ARI, Kamailio JSONRPC, LiveKit Twirp API, SeaweedFS S3 | tenants, extensions, trunks, numbers, routing, IVR, queues, agents, recordings, CDR, quotas |
| Navin Enterprise | Manager API (existing platform_manager domain) | reads the inventory and the state of the services; every infrastructure operation is asked of the Manager |
The Control Plane runs no system command. The Manager manages no extension, IVR, queue or business rule.
2. Services of the Manager catalogue
| Service | Components | Methods | Role |
|---|---|---|---|
asterisk | asterisk (pool) | package | PBX: PJSIP, dialplan, queues, voicemail, ConfBridge, MixMonitor, ARI, AMI, CDR and CEL |
kamailio | kamailio (at least 2 in HA) | package | SIP edge: TLS, WSS, NAT, anti-flood, anti-bruteforce, dispatcher toward Asterisk and LiveKit SIP |
rtpengine | rtpengine | package | optional: RTP anchoring, difficult NAT, media interconnection; never installed by default |
livekit | livekit-server | binary, podman | existing, completed without changing a deployment that works |
livekit-sip | livekit-sip | podman | SIP gateway to the LiveKit rooms |
livekit-egress | livekit-egress | podman | LiveKit recordings to SeaweedFS |
livekit-ingress | livekit-ingress | podman | optional, not needed by telephony (RTMP, WHIP) |
livekit-agents | livekit-agents (workers) | python | runs the Navin voice AI agents |
Default ports (the planner refuses a conflict on one host):
| Service | Port | Exposure |
|---|---|---|
| Kamailio | 5060 UDP and TCP, 5061 TLS (SIP); 7443 WSS (softphones) | public (carriers, phones) |
| Kamailio | 5071 HTTP (JSONRPC and /metrics) | administration network |
| Asterisk | 5070 UDP and TCP (SIP from Kamailio only) | internal signalling network |
| Asterisk | 8088 HTTP, 8089 HTTPS (ARI, /metrics); 5038 AMI, 5039 AMI TLS | administration network |
| Asterisk | 10000 to 19999 UDP (RTP, SRTP, DTLS-SRTP) | media network |
| LiveKit SIP | 5090 UDP and TCP (SIP); 20000 to 29999 UDP (RTP) | internal and media |
| RTPengine | 2223 UDP (ng protocol); 30000 to 39999 UDP | administration and media |
| LiveKit Server | 7880 (signalling), 50000 to 50100 UDP (existing) | existing |
AMI, ARI, JSONRPC and the metrics ports are never public: they listen on the administration address of the host and the Manager firewall opens them only to the declared sources.
3. Delivery of the functional configuration
- Asterisk. The Manager installs the system files (
asterisk.conf,modules.conf,pjsip.confwith the transports,extensions.conf,queues.conf,voicemail.conf,confbridge.conf,manager.conf,ari.conf,http.conf,rtp.conf,prometheus.conf,cdr.conf,cel.conf); each includes a managed file (#tryinclude pjsip_navin.conf,extensions_navin.conf,queues_navin.conf,voicemail_navin.conf,confbridge_navin.conf). Navin Enterprise compiles these managed files per PBX pool from the tenants, extensions, trunks, numbers, rules, IVR and queues; it validates them, versions them (text, SHA-256 fingerprint, author), delivers them to every node of the pool through AMI (CreateConfig,UpdateConfig), activates them through AMI (pjsip reload,dialplan reload,queue reload all,voicemail reload,module reload app_confbridge.so), reads the result back (GetConfig) and can go back to the previous version. ARI is used for call control (channels, bridges, recordings, transfers); AMI also carries the events (CDR throughcdr_manager, CEL throughcel_manager, contact and queue states). - Naming. Short tenant id
tid=tfollowed by the first 12 hexadecimal characters of its UUID. Endpoints{tid}-{extension}, contexts{tid}-internal,{tid}-inbound,{tid}-outbound,{tid}-ivr-{flow}, queues{tid}-{queue},accountcode= UUID of the tenant, variableNAVIN_TENANTon every channel. No context of a tenant references an object of another tenant; the compiler checks it. - Kamailio. The Manager writes the dispatcher list from the topology (set 1: shared Asterisk pool, set 2: LiveKit
SIP, sets 100 and above: dedicated pools). Navin Enterprise pushes the routing of the tenants through JSONRPC into the
hash tables
tenant_domains(SIP domain to tenant and set) anddid_routes(E.164 number to tenant, set and branchpbxorai), reconciles at regular intervals and after every Kamailio restart (core.uptime), and drives the drain of the destinations (dispatcher.set_state). The Kamailio instances replicate these tables through DMQ. - LiveKit SIP. Navin Enterprise creates through the LiveKit API the inbound and outbound trunks and the dispatch
rules of every tenant (names prefixed by
tid, metadatatenant_id), starts the outbound calls of the agents (CreateSIPParticipant) and the transfers to an extension (TransferSIPParticipant, SIP REFER). - Two distinct branches. PBX branch: Kamailio to Asterisk. Direct AI branch: Kamailio to LiveKit SIP (number routed
ai). AI branch through the PBX: Asterisk dialsPJSIP/{agent}@livekit-sipfrom an IVR or a queue. The AI to human transfer goes through a REFER to Kamailio, which routes the extension to its Asterisk. - Correlation. Asterisk sets the header
X-Navin-Call-Id(UUID); LiveKit SIP copies it into a participant attribute; the Navin call session linksX-Navin-Call-Id, the Asteriskuniqueidandlinkedid, the SIPCall-ID, the LiveKit room and participant.
4. Data of Navin Enterprise
Tables of the eai schema, all with tenant_id, isolated by the existing tenancy mechanisms of the Control Plane:
telephony_tenants (model shared or dedicated, SIP domain, pool, quotas, retention), pbx_instances (shared or
dedicated pool, Manager service, references of the AMI and ARI secrets), sip_trunks, phone_numbers, extensions,
routing_rules, ivr_flows and their versions, call_queues, queue_members, telephony_agents (humans),
voice_agents (AI), telephony_config_versions (publications), call_sessions, call_events, call_recordings,
voicemail_messages, telephony_quotas. The existing audit journal of the Control Plane is reused, not duplicated.
SIP passwords, trunk secrets, AMI and ARI credentials: in the existing vault, never returned by the API (write only
fields, has_secret).
5. SeaweedFS storage
One bucket navin-telephony, opaque keys tenants/{tenant_uuid}/{category}/{yyyy}/{mm}/{uuid}, categories
call-recordings, voicemail, ivr-prompts, conference-recordings, ai-voice-recordings, audio-exports. The
objects are encrypted by Navin Enterprise before upload. Reading and download only through Navin Enterprise: signed URLs
of a few minutes, permission checks, audit; the S3 credentials never leave the server. Asterisk recordings: MixMonitor
writes into recording/navin/{tid}/; Navin Enterprise fetches them through ARI (GET /recordings/stored/{name}/file),
encrypts them, uploads them, then deletes them through ARI. LiveKit Egress writes into the bucket navin-livekit-egress
with credentials limited to that bucket; at the end of a recording (signed webhook), Navin Enterprise moves it into the
tenant layout.
6. WebRTC softphone
The portal softphone uses JsSIP (MIT) in SIP over secure WebSocket toward Kamailio (WSS, path), which relays to the
Asterisk of the tenant; DTLS-SRTP media with ICE between the browser and Asterisk (webrtc=yes). The browser never
receives the SIP password of the extension: Navin Enterprise issues ephemeral credentials (Kamailio auth_ephemeral
module, HMAC with a shared secret kept in the vault, one hour at most); the WebRTC endpoints of Asterisk accept only the
Kamailio addresses. A LiveKit room is not an extension.
7. Multi-tenant
shared model: shared Asterisk pool, isolation by contexts, SIP domains, LiveKit prefixes, storage prefixes and
authorisations. dedicated model: Asterisk pool (and, when needed, LiveKit SIP) dedicated to the tenant, its own
dispatcher set. Quotas per tenant: concurrent calls, calls per second (CPS, enforced by Kamailio), allowed destinations
and countries, maximum duration, retention of recordings.
8. High availability: guarantees per scenario
| Failure | New calls | Calls in progress |
|---|---|---|
| One Kamailio instance | taken by the other instance (DNS SRV, several addresses at the carrier, or a network load balancer) | the dialogs routed by the lost instance fail on their next request |
| One Asterisk node of the pool | routed to the other nodes as soon as the OPTIONS probe of the dispatcher marks it down | lost: there is no call state shared between Asterisk nodes |
| One LiveKit SIP or LiveKit Server node | routed to the other nodes | lost for the SIP participants of that node |
| One AI agent worker | taken by another worker | the agent session stops; the fallback rule routes to a human queue |
| PostgreSQL, Redis, SeaweedFS | existing HA modes of the catalogue (Patroni, Sentinel, replication) | depends on the service |
A virtual IP address is not a universal solution; no capacity and no call survival is announced without a test.
9. Observability
Metrics: res_prometheus of Asterisk, xhttp_prom of Kamailio, Prometheus ports of LiveKit, LiveKit SIP and Egress,
collected by the Prometheus of the catalogue; logs through Alloy; alerts through Alertmanager; business indicators
(calls, CPS, quality, queues, consumption) computed by Navin Enterprise from the CDR, CEL and events.
10. Licences
Asterisk (GPL-2.0), Kamailio (GPL-2.0-or-later), RTPengine (GPL-3.0) and JsSIP (MIT) stay separate components, used through their documented network interfaces; no GPL code enters the proprietary code of Navin. The redistribution of the GPL binaries in the offline bundle comes with the notices and the corresponding sources.
Consequences
- The Manager gains five services and configuration templates; Navin Enterprise gains a telephony domain, its migrations, its compilers and a section of the portal.
- The Control Plane depends on the Asterisk AMI and ARI, the Kamailio JSONRPC and the LiveKit API, reached through the
bindings of the
navin-enterpriseservice of the catalogue. - Load tests and multi-host failure tests run on a dedicated environment with SIPp; no test is sent to a carrier without its agreement.