I want to implement my own custom sip to my self h...
# ask-ai
n
I want to implement my own custom sip to my self hosted livekit instance and project can you give me step by step roadmap for how to do that? You have to be specific and clear.
✅ 1
t
Thanks for reaching out, Berfin. I'm an AI assistant and I'm here to help. Give me a moment while I research this topic.
Thanks — I’m glad you want a clear, step-by-step roadmap. I’ll walk you through a concrete plan to implement a custom SIP integration for your self‑hosted LiveKit instance and project. I’ll highlight exactly what to deploy, configure, and test. If you want code samples in a specific language (Go, Python, or JS) or details about your SIP provider configuration, tell me which and I’ll include those next. Acknowledgement of your request • You asked for a specific, clear step-by-step roadmap to add custom SIP to a self‑hosted LiveKit instance and project. I’ll cover deployment, trunk setup (inbound/outbound), dispatch rules, creating SIP participants, optional features (noise cancellation, recording), security, and testing. Roadmap — step by step 1) Prepare your environment • Ensure your LiveKit server is running and reachable (public hostname or IP) and you have admin API credentials for the instance. • Plan networking: public IP/port for SIP traffic, TLS certs for SIP over TLS, and any NAT/firewall rules for RTP/UDP ranges. 2) Deploy the LiveKit SIP service • Deploy the separate component called livekit-sip alongside your main LiveKit server (self‑hosted requires this). It must be able to call the LiveKit internal APIs to create rooms and participants. • Expose the SIP service to the public internet (or to your SIP provider) on the port(s) you choose (UDP/TCP/TLS). Configure TLS certs if you will use SIP over TLS. 3) Choose and configure a SIP trunk provider • Select a provider (examples: Twilio, Telnyx, Plivo, Telco of choice). • Buy or port the phone numbers you’ll use. • Obtain auth method from the provider: credential (username/password) or IP-based allowlist. You’ll use these to register/accept calls from the provider into your SIP endpoint. • Point the provider’s SIP destination to your livekit-sip public address:port (and TLS if using TLS). 4) Configure inbound trunks in LiveKit • Create an inbound trunk record in LiveKit that represents the SIP provider connection and the phone numbers that route to LiveKit. • While creating the trunk, set: ◦ allowed IP addresses (to restrict which SIP providers can send calls) ◦ phone numbers (the numbers the trunk will accept) ◦ optional settings such as Krisp noise cancellation if you want it enabled at trunk level • This registration tells LiveKit which numbers map to this trunk. 5) Create dispatch rules to route inbound calls to rooms • Decide routing strategy: ◦ Single room for all calls ◦ New room per call (recommended for typical call flows) using a prefix like
call-{uuid}
◦ Route based on dialed number (DNIS) • Create dispatch rules and attach them to the inbound trunk. Each rule can: ◦ Provide a
room_prefix
to auto-create rooms ◦ Include optional room configuration (e.g., auto-recording/egress) ◦ Optionally set a PIN or other routing metadata • When a call arrives, the SIP service uses the dispatch rule to create/join the SIP participant to the proper LiveKit room. 6) Handle SIP participants (inbound and outbound) • Inbound: the SIP participant is created automatically when the call arrives and is routed via the dispatch rule. • Outbound: to place calls from LiveKit to the PSTN, create an outbound trunk with your provider credentials and then call the LiveKit API method to create a SIP participant (e.g.,
CreateSIPParticipant
) specifying: ◦ outbound trunk ID ◦ destination number ◦ target room name ◦ optional Krisp and caller name • Ensure your code handles the SIP participant lifecycle (answer, hold, transfer, hangup). 7) Optional features you should plan for • Noise cancellation: enable Krisp at trunk or participant creation if you need noise suppression. • Auto-recording / egress: configure room-level recording if you need call recordings saved to object storage. • Webhooks/events: subscribe to LiveKit/SIP lifecycle events (call started/ended) for logging, metrics, and integration with your backend. • Agent integration: if using voice agents, ensure your agent orchestration will join rooms automatically and handle media/DTMF as needed. 8) Security and transport • Use SIP over TLS and SRTP for secure signaling and media where possible. • Use IP allowlists on trunks and provider side to limit who can reach your SIP endpoint. • Limit credentials and rotate them periodically. 9) Monitoring and logging • Enable detailed logs on livekit-sip and LiveKit for SIP signaling and RTP. • Monitor call failures, media negotiation errors, and codec mismatches. • Use your SIP provider logs to correlate inbound/outbound call signaling. 10) Test thoroughly (stepwise) • Provider->LiveKit inbound test: a. Have the provider send a test incoming call to the number. b. Verify the call reaches your livekit-sip endpoint. c. Verify LiveKit creates the intended room and SIP participant and that audio flows. • LiveKit->Provider outbound test: a. Create an outbound trunk and use
CreateSIPParticipant
to place a call. b. Verify the provider receives the outbound INVITE and audio is bidirectional. • Verify features: DTMF, call hold/transfer, SRTP (if enabled), and recording if configured. • Validate failure modes: misconfigured codec, firewall blocking RTP, provider auth failure. 11) Troubleshooting checklist (common issues) • No audio: check RTP port ranges, NAT, and firewall rules (RTP often blocked). • One-way audio: check NAT traversal, symmetric NAT, and SRTP mismatches. • Calls not reaching LiveKit: verify provider points to correct public IP/port and that trunk allowlist includes provider IPs. • Codec negotiation failures: ensure supported audio codecs are configured (e.g., PCMU/PCMA/opus). • Registration/auth errors: verify provider credentials or IP allowlist are correct. What I can provide next • If you want, I can: ◦ Produce concrete API code examples for creating trunks, dispatch rules, and SIP participants in Python, JavaScript, or Go. ◦ Give a recommended RTP port range and firewall/NAT rules for common deployments. ◦ Provide a short checklist for configuring Twilio/Telnyx specifically (pick provider). ◦ Help map your desired routing behavior (single room vs per-call rooms vs DNIS routing) into exact API fields. Next question for you • Which language do you prefer for code samples (Python, JS, Go)? • Do you already have a SIP provider in mind (Twilio, Telnyx, etc.)? • Do you plan to enable Krisp noise cancellation and call recording? If you tell me the language and provider, I’ll produce precise API examples and the exact commands to run on your self-hosted instance. Sources: Agents telephony integration | LiveKit Documentation | sip | livekit/livekit_composite | DeepWiki | Making calls overview | LiveKit Documentation | examples/frontdesk | livekit/livekit_composite | DeepWiki | Agents (Python) | livekit/livekit_composite | DeepWiki, with interactive elements
n
where will I add all of those, which project part and files
t
Thanks — I’ll map exactly where to put each SIP-related piece in your self‑hosted LiveKit project. I’ll assume a typical split between a backend/control plane service (manages trunks & dispatch rules) and your agent/worker (handles calls). If your project is structured differently, tell me the language and a short tree and I’ll adapt. Quick question before I give file-level examples • Which language is your backend and agent written in? (Python, Node/JS, or Go) Answer that and I’ll produce exact filenames and sample snippets tailored to your repo. Where to put each SIP responsibility (high level) • Backend / control-plane (telephony management): ◦ Purpose: create trunks, create dispatch rules, manage trunk credentials, configure auto-egress/recording, and expose any admin endpoints or scripts to update SIP config. ◦ Where: a dedicated service or CLI module in your backend project (not inside agent code). ◦ Typical files: sip_setup.py / sip_manager.py / services/sip/*.js / cmd/sip_manager.go ◦ Runs: as a one-time setup script, cron/CI job, or an admin HTTP/API endpoint your ops team calls. • Agent / worker (conversation logic): ◦ Purpose: join rooms, run the voice agent, respond to calls, optionally initiate outbound calls using CreateSIPParticipant. ◦ Where: agent codebase (separate process from the LiveKit server and from the control-plane). ◦ Typical files: agent.py / entrypoint.py / agents/voice_agent.js / handlers/sip_agent.go ◦ Note: Agents should not manage trunk lifecycle (creation/deletion); they only react to rooms and may call the API to create a SIP participant for outbound calls. • Environment / config: ◦ Purpose: store LiveKit API credentials, SIP trunk IDs, provider credentials, RTP port ranges, TLS cert locations. ◦ Where: .env, config/_.yaml or config/_.toml, or secrets manager. ◦ Typical keys: LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET, SIP_INBOUND_TRUNK_ID, SIP_OUTBOUND_TRUNK_ID • livekit-sip service (infrastructure repo or k8s manifests): ◦ Purpose: the actual SIP gateway process that speaks SIP to the provider and communicates with LiveKit. ◦ Where: infra/ or deployments/ (k8s manifests, docker-compose files) ◦ Typical files: deployments/livekit-sip-deployment.yaml, helm/values.yaml, docker-compose.yml Concrete placement examples (choose your stack) • If your backend is Python and agent is Python: ◦ Backend: ▪︎ repo/backend/sip_setup.py — scripts that call LiveKit API to create trunks and dispatch rules ▪︎ repo/backend/services/sip_manager.py — wrapper functions to list/create/update trunks and rules ▪︎ repo/backend/routes/admin_sip.py — admin HTTP endpoints to trigger trunk creation or update ◦ Agent: ▪︎ repo/agent/agent_entrypoint.py — agent startup and Room join logic ▪︎ repo/agent/functions/outbound_call.py — function tool that calls
CreateSIPParticipant
◦ Config: ▪︎ repo/backend/.env • LIVEKIT_URL= • LIVEKIT_API_KEY= • LIVEKIT_API_SECRET= • SIP_OUTBOUND_TRUNK_ID= ▪︎ repo/infra/livekit-sip-deployment.yaml • If your backend is Node/JS and agent is Node/JS: ◦ Backend: ▪︎ src/telephony/sipSetup.js — create trunks, dispatch rules using LiveKit server SDK or REST API ▪︎ src/routes/telephonyAdmin.js — admin endpoints to manage trunks ◦ Agent: ▪︎ src/agents/voiceAgent.js — agent logic ▪︎ src/agents/tools/makeCall.js — calls LiveKit API to create SIP participant for outbound calls ◦ Config: ▪︎ config/default.yml or .env for keys ▪︎ infra/docker-compose.yml or helm chart for livekit-sip Exactly what code goes in each file (summary) • sip_setup.* (backend) ◦ Create inbound trunk(s) with phone numbers and allowed addresses ◦ Create dispatch rule(s) attached to trunks with room_prefix or DNIS routing ◦ Optionally configure krisp_enabled and auto-egress in room_config • sip_manager.* (backend library) ◦ List/update/delete trunks and dispatch rules ◦ Helper to map provider IPs -> trunk allowlist • admin_sip.* (backend endpoint) ◦ Expose secure endpoints for ops to re-run or change trunk configs • agent entrypoint (agent) ◦ Join rooms, accept SIP participants already created by dispatch rules ◦ Register function tool to make outbound calls via CreateSIPParticipant when needed • infra manifests ◦ livekit-sip deployment and service, TLS secrets, and firewall/NAT rules for RTP ports Where to store secrets and IDs • Put API keys, trunk credentials, and trunk IDs in environment variables or a secrets manager, not in source control. • Example keys: LIVEKIT_API_KEY, LIVEKIT_API_SECRET, SIP_PROVIDER_USERNAME, SIP_PROVIDER_PASSWORD, SIP_INBOUND_TRUNK_ID Next steps I can provide • If you tell me your language (Python/JS/Go) I’ll: ◦ Provide a ready-to-run example file (sip_setup.py or sipSetup.js) that creates an inbound trunk and dispatch rule. ◦ Provide an agent snippet showing how to place an outbound call (
CreateSIPParticipant
). ◦ Show an example k8s manifest or docker-compose snippet to deploy livekit-sip and required ports. Tell me which language you want and paste a short repo tree (3–6 top-level files/folders) if you want me to specify exact file contents. Sources: examples/voice_agents | livekit/livekit_composite | DeepWiki | sip | livekit/livekit_composite | DeepWiki | Python SDKs | livekit/livekit_composite | DeepWiki | examples/dtmf | livekit/livekit_composite | DeepWiki | SIP Lifecycle Management Agent | LiveKit Documentation, with interactive elements
n
I use python, I have a ready project running on a vm with both livekit instance and project files. Please provide your explanations for this direction
t
Great — since you’re running a self‑hosted LiveKit instance and your project is Python on a VM, here’s a clear, practical map of exactly which files to add or modify, where to put them, and what each one should do. I’ll keep it executable and focused so you can copy/paste and run. High‑level structure I recommend (example repo layout) • infra/ # deployment manifests for livekit-sip ◦ livekit-sip-deployment.yaml ◦ firewall.md • backend/ # control-plane service that manages SIP trunks & rules ◦ sip_setup.py ◦ sip_manager.py ◦ routes.py (optional admin HTTP endpoints) ◦ requirements.txt • agent/ # your agent/worker handling rooms and calls ◦ agent_entrypoint.py ◦ outbound_call.py ◦ requirements.txt • .env # environment variables (not checked into git) • README.md Which component gets what (short summary) • infra/: Deployment files for the livekit-sip gateway process and any firewall/NAT notes. • backend/: Control‑plane code that creates and manages SIP trunks and dispatch rules using the LiveKit Server SDK (Python). This is where you put
sip_setup.py
and
sip_manager.py
. • agent/: Agent logic that joins rooms and optionally initiates outbound calls via LiveKit API (
CreateSIPParticipant
). • .env: Store secrets and trunk IDs (never in source). Detailed file contents and purpose 1) infra/livekit-sip-deployment.yaml • Purpose: Deploy the livekit-sip process that accepts SIP from your provider and talks to LiveKit. • What to include: ◦ Service/Deployment references to the livekit-sip image ◦ Expose SIP ports (UDP/TCP 5060 or custom, and TLS 5061 if using) ◦ RTP port range (e.g., 10000–20000) in Service/Firewall rules ◦ TLS secret mounting if using SIP over TLS • Notes: If you use a VM and systemd/docker-compose, put equivalent docker-compose or systemd unit here. 2) backend/sip_setup.py (run once or when reconfiguring) • Purpose: Create inbound trunk(s) and dispatch rules, optionally configure auto‑egress (recording) and Krisp. • Run: python backend/sip_setup.py • Minimal runnable example (adapt creds & phone numbers):
Copy code
# backend/sip_setup.py
import os, asyncio
from livekit import api
from livekit.api import (
    CreateSIPInboundTrunkRequest, SIPInboundTrunkInfo,
    CreateSIPDispatchRuleRequest, SIPDispatchRule, SIPDispatchRuleIndividual
)

async def setup():
    lk = api.LiveKitAPI(
        url=os.environ["LIVEKIT_URL"],
        api_key=os.environ["LIVEKIT_API_KEY"],
        api_secret=os.environ["LIVEKIT_API_SECRET"]
    )

    # Create inbound trunk
    trunk_req = CreateSIPInboundTrunkRequest(
        trunk=SIPInboundTrunkInfo(
            name="vm-inbound-trunk",
            numbers=[os.environ.get("PHONE_NUMBER")],  # e.g. "+1234567890"
            krisp_enabled=True
        )
    )
    trunk = await lk.sip.create_sip_inbound_trunk(trunk_req)
    print("Created trunk id:", trunk.sip_trunk_id)

    # Dispatch rule: new room per call prefixed with "call-"
    dispatch_req = CreateSIPDispatchRuleRequest(
        trunk_ids=[trunk.sip_trunk_id],
        rule=SIPDispatchRule(
            dispatch_rule_individual=SIPDispatchRuleIndividual(room_prefix="call")
        )
    )
    rule = await lk.sip.create_sip_dispatch_rule(dispatch_req)
    print("Created dispatch rule id:", rule.sip_dispatch_rule_id)

    # Persist ids to environment/secrets store or print them for manual copy
    print("Set SIP_INBOUND_TRUNK_ID and SIP_DISPATCH_RULE_ID in your .env")

if __name__ == "__main__":
    asyncio.run(setup())
• Place this file at backend/sip_setup.py. Keep it idempotent in production (check existing trunks/rules first) or run in a controlled CI job. 3) backend/sip_manager.py • Purpose: Reusable functions to list/update/delete trunks and rules. Use from scripts or HTTP admin endpoints. • Suggested functions: ◦ create_inbound_trunk(phone_numbers, krisp_enabled) ◦ create_dispatch_rule(trunk_id, room_prefix, room_config=None) ◦ list_trunks(), delete_trunk(trunk_id) • Use this in sip_setup.py and any admin endpoints. 4) backend/routes.py (optional) • Purpose: If you want a secure web UI or API to reconfigure trunks without SSH. • Example endpoints: ◦ POST /admin/sip/setup -> runs sip_setup.create_inbound_trunk ◦ GET /admin/sip/trunks -> lists trunks • Secure with token auth or restrict to local network. 5) agent/agent_entrypoint.py • Purpose: Agent process that is dispatched into rooms created by the dispatch rules. It should join rooms, handle STT/LLM/ TTS, etc. • You do not put trunk creation logic here. The agent just joins rooms created by LiveKit when SIP calls arrive. • Minimal sketch:
Copy code
# agent/agent_entrypoint.py
import os
from livekit_agents import Server, JobContext  # conceptual
# Your agent framework imports...

async def entrypoint(ctx: JobContext):
    # ctx.room is the LiveKit room for a SIP call created by dispatch rule
    # Implement your voice agent/session here
    await handle_call(ctx.room)

if __name__ == "__main__":
    # Start agent worker that listens for jobs dispatched by LiveKit
    Server.run(entrypoint)
6) agent/outbound_call.py • Purpose: Example function to place an outbound call from the agent using CreateSIPParticipant. • Example:
Copy code
# agent/outbound_call.py
import os
from livekit import api

async def place_outbound_call(room_name, to_number):
    lk = api.LiveKitAPI(url=os.environ["LIVEKIT_URL"],
                        api_key=os.environ["LIVEKIT_API_KEY"],
                        api_secret=os.environ["LIVEKIT_API_SECRET"])
    await lk.sip.create_sip_participant(
        api.CreateSIPParticipantRequest(
            sip_trunk_id=os.environ["SIP_OUTBOUND_TRUNK_ID"],
            sip_call_to=to_number,
            room_name=room_name,
            participant_name="agent-outbound",
            krisp_enabled=True
        )
    )
• Call this from your agent logic or a function tool when you want the agent to make an outbound call. 7) .env (store secrets and IDs) • LIVEKIT_URL=https//your vm7880 • LIVEKIT_API_KEY=... • LIVEKIT_API_SECRET=... • PHONE_NUMBER=+1234567890 • SIP_INBOUND_TRUNK_ID= (after running sip_setup) • SIP_DISPATCH_RULE_ID= (after running sip_setup) • SIP_OUTBOUND_TRUNK_ID= (if you create outbound trunk) • S3_* or recording credentials if you enable auto-egress Best practices and operational tips • Keep credentials and trunk IDs in a secrets manager or
.env
outside version control. • Run sip_setup.py once (or from CI) and record returned trunk and dispatch IDs. • Configure your SIP provider to send calls to your livekit-sip public address (VM public IP or load balancer) and the port you expose. Provide their IPs in
allowed_addresses
if you want extra security. • Open RTP port range in your firewall (e.g., 10000–20000 UDP) and ensure NAT mapping for those ports. • Use SIP over TLS and SRTP if your provider supports it and you want encrypted signaling & media. • For troubleshooting: ◦ If no audio, check RTP ports/NAT. ◦ If calls don’t arrive, verify provider points to the correct IP:port and that the trunk allowlist includes the provider’s IP. ◦ Check livekit-sip logs for SIP INVITE/401/403 or codec negotiation errors. What I can produce next (pick one) • A full, ready-to-run backend/sip_setup.py adapted to the exact versions of your SDK (I used generic types above). Paste your repo root (ls -la) or the contents of your current backend folder and I’ll generate the exact file. • A docker-compose snippet for livekit-sip with RTP ports and TLS mounting tuned for VM deployment. • A sample agent handler (full agent_entrypoint.py) that joins the room and records audio to verify media flow. Tell me which of those you want next (or paste your repo tree) and I’ll produce the exact files ready to drop into your VM. Sources: examples/bank-ivr | livekit/livekit_composite | DeepWiki | sip | livekit/livekit_composite | DeepWiki | Python SDKs | livekit/livekit_composite | DeepWiki | examples/frontdesk | livekit/livekit_composite | DeepWiki | Agents (Python) | livekit/livekit_composite | DeepWiki, with interactive elements
n
I just want to implement inbound calls, rearrange your output behalf of this
t
Thanks — I’ll focus only on inbound calls and give a concise, practical plan you can drop into your VM project. I’ll show exactly which files to add, what each does, and the precise Python code to create an inbound trunk and dispatch rule so incoming PSTN calls reach LiveKit rooms. Assumptions • You have LiveKit and livekit-sip running on your VM and reachable from the public internet. • You have a SIP provider/phone number ready to point to your livekit-sip public address. • Your project is Python and already runs on the same VM. Recommended repo layout (minimal) • infra/ ◦ livekit-sip-deployment.yaml (or docker-compose/systemd notes) ◦ firewall.md • backend/ ◦ sip_setup.py ← create inbound trunk & dispatch rule (run once) ◦ sip_manager.py ← reusable helper functions (optional) ◦ requirements.txt • agent/ ◦ agent_entrypoint.py ← your existing agent (unchanged for inbound) • .env ← secrets & trunk IDs (not checked in) Exact files and contents 1) backend/sip_setup.py • Purpose: Create an inbound SIP trunk and attach a dispatch rule that creates a room per call (prefix "call-"). • Run once (or via a controlled CI job) to register phone numbers and routing in LiveKit. Place this file at backend/sip_setup.py and fill environment variables in .env. Code (copy into backend/sip_setup.py):
Copy code
import os
import asyncio
from livekit import api
from livekit.api import (
    CreateSIPInboundTrunkRequest, SIPInboundTrunkInfo,
    CreateSIPDispatchRuleRequest, SIPDispatchRule, SIPDispatchRuleIndividual,
    ListSIPInboundTrunkRequest, ListSIPDispatchRuleRequest,
)

async def setup_inbound_trunk():
    lk = api.LiveKitAPI(
        url=os.environ["LIVEKIT_URL"],
        api_key=os.environ["LIVEKIT_API_KEY"],
        api_secret=os.environ["LIVEKIT_API_SECRET"],
    )

    phone_number = os.environ["PHONE_NUMBER"]  # e.g. "+1234567890"

    # Optional: avoid duplicate trunks by checking existing numbers
    existing = await lk.sip.list_sip_inbound_trunk(ListSIPInboundTrunkRequest())
    for t in existing.items:
        if phone_number in (t.numbers or []):
            print("Trunk already exists for number:", phone_number)
            trunk = t
            break
    else:
        # Create inbound trunk
        trunk_req = CreateSIPInboundTrunkRequest(
            trunk=SIPInboundTrunkInfo(
                name="vm-inbound-trunk",
                numbers=[phone_number],
                krisp_enabled=True,  # optional
                # allowed_addresses=[os.environ.get("SIP_PROVIDER_IP")]  # optional
            )
        )
        trunk = await lk.sip.create_sip_inbound_trunk(trunk_req)
        print("Created trunk id:", trunk.sip_trunk_id)

    # Create dispatch rule: each call -> new room with prefix "call-"
    # Check for existing rule first
    existing_rules = await lk.sip.list_sip_dispatch_rule(ListSIPDispatchRuleRequest())
    rule_exists = False
    for r in existing_rules.items:
        # crude check: same trunk attached and same rule type; refine as needed
        if trunk.sip_trunk_id in (r.trunk_ids or []):
            rule_exists = True
            rule = r
            print("Found existing dispatch rule:", r.sip_dispatch_rule_id)
            break

    if not rule_exists:
        dispatch_req = CreateSIPDispatchRuleRequest(
            trunk_ids=[trunk.sip_trunk_id],
            rule=SIPDispatchRule(
                dispatch_rule_individual=SIPDispatchRuleIndividual(room_prefix="call")
            ),
        )
        rule = await lk.sip.create_sip_dispatch_rule(dispatch_req)
        print("Created dispatch rule id:", rule.sip_dispatch_rule_id)

    # Output values to save in your .env or secrets store
    print("EXPORT THESE VALUES:")
    print("SIP_INBOUND_TRUNK_ID=", trunk.sip_trunk_id)
    print("SIP_DISPATCH_RULE_ID=", rule.sip_dispatch_rule_id)

if __name__ == "__main__":
    asyncio.run(setup_inbound_trunk())
2) backend/sip_manager.py (optional but handy) • Purpose: helper functions to list/delete trunks or rules later. • Put simple wrappers here you can call from admin endpoints or CLI. Example skeleton (backend/sip_manager.py):
Copy code
import os
from livekit import api

def client():
    return api.LiveKitAPI(
        url=os.environ["LIVEKIT_URL"],
        api_key=os.environ["LIVEKIT_API_KEY"],
        api_secret=os.environ["LIVEKIT_API_SECRET"],
    )
# Add functions: list_trunks(), delete_trunk(id), list_rules(), delete_rule(id)
3) agent/agent_entrypoint.py • Purpose: No changes required for inbound — when an inbound call arrives LiveKit will create a room (e.g., call-*) and dispatch your agent. Ensure your agent is running and registered to accept jobs. • Confirm the agent joins rooms by room name and handles audio. If you want, paste your agent file and I’ll verify it’s ready. 4) .env (store on VM, not in git) • LIVEKIT_URL=https//your vm7880 • LIVEKIT_API_KEY=... • LIVEKIT_API_SECRET=... • PHONE_NUMBER=+1234567890 Deployment / provider configuration checklist • livekit-sip reachable: Configure your SIP provider to send calls to your livekit-sip public IP/port (e.g., udp/tcp 5060 or TLS 5061). Provide their docs with your public endpoint. • Provider auth: Use credential auth or IP allowlist; if using IP allowlist, set allowed_addresses when creating the trunk. • Firewall/NAT: Open RTP ports (e.g., UDP 10000–20000) and SIP port(s). Map them correctly in NAT. • TLS/SRTP: If you want encrypted signaling/media, configure TLS certs and enable SRTP. Otherwise start with UDP for testing. How to run the setup 1. SSH to your VM and activate your Python venv. 2. Install SDK: pip install livekit-api 3. Put your credentials in backend/.env (export or load with dotenv). 4. Run: python backend/sip_setup.py 5. Copy SIP_INBOUND_TRUNK_ID and SIP_DISPATCH_RULE_ID into .env once created. Testing inbound calls 1. Point your provider’s number to your livekit-sip endpoint. 2. Call the phone number from another line. 3. Confirm: ◦ livekit-sip logs show incoming INVITE. ◦ LiveKit creates a room named like call-id. ◦ Your agent is dispatched to and joins the room. ◦ Two‑way audio flows (if not, check RTP ports/NAT). Troubleshooting quick hits • No INVITE hits livekit-sip: verify provider points to correct public IP/port and firewall allows SIP port. • Call reaches livekit-sip but no room created: check livekit-sip can reach LiveKit API (network, API key). • One-way audio: check RTP port ranges on VM and NAT mapping. • Codec mismatch: ensure provider supports common audio codecs (PCMU/PCMA/opus). If you want next • I can produce a complete ready-to-run backend/sip_setup.py adapted to the exact versions on your VM if you paste: ◦ output of pip freeze or your current requirements.txt, and ◦ your LIVEKIT_URL value (or confirm port and TLS settings). • Or I can generate a small docker-compose snippet for livekit-sip + LiveKit on a single VM to ensure correct ports and TLS mounting. Tell me which of those you want and I’ll generate the exact files/commands. , with interactive elements
n
this assumption is not true: You have LiveKit and livekit-sip running on your VM and reachable from the public internet. I just have running LiveKit not livekit-sip. rewrite your clear suggestions
t
Thanks — that helps. Since you currently have only LiveKit running (no livekit-sip), I’ll give a concise, practical plan you can follow on your VM: how to deploy livekit-sip, secure networking, and then exactly where and what Python code to add to enable inbound calls. This will be focused on inbound-only calls. Summary of steps you’ll take 1. Deploy livekit-sip on your VM (Docker or binary). 2. Open and map required ports (SIP signaling + RTP range) and add TLS if desired. 3. Configure your SIP provider to point to your livekit-sip endpoint. 4. Add Python code to your project to create an inbound trunk and a dispatch rule so incoming PSTN calls create rooms in LiveKit. 5. Test and troubleshoot. A. Deploy livekit-sip on your VM Choose one method. Docker is easiest and keeps things isolated. Option 1 — Docker (recommended) • Create a docker-compose.yml (example file path: infra/docker-compose.yml) with: ◦ livekit-sip service image (use the official livekit-sip image) ◦ Environment variables pointing to your LiveKit URL and API credentials ◦ Ports: ▪︎ SIP (UDP/TCP 5060) and SIP-TLS (TCP 5061) if using TLS ▪︎ RTP range (e.g., UDP 10000–20000) ◦ Mount TLS certs if using SIP over TLS Example (conceptual — you’ll adapt image tag and envs):
Copy code
version: '3.7'
services:
  livekit-sip:
    image: livekit/livekit-sip:latest
    restart: unless-stopped
    environment:
      LIVEKIT_URL: "https://localhost:7880"      # your LiveKit public/internal URL
      LIVEKIT_API_KEY: "your_api_key"
      LIVEKIT_API_SECRET: "your_api_secret"
      # Additional configs as required by livekit-sip
    ports:
      - "5060:5060/udp"
      - "5060:5060/tcp"
      - "5061:5061/tcp"    # if using TLS
      - "10000-20000:10000-20000/udp"
    volumes:
      - ./certs:/etc/ssl/certs   # if mounting TLS certs
• Start it: docker compose up -d • Confirm logs: docker compose logs -f livekit-sip Option 2 — Binary or systemd • Download the livekit-sip binary for your OS, configure environment variables or config file with your LIVEKIT_URL/API keys, and start it as a systemd service. Ensure SIP/TLS certs are in a path the service can read. B. Network & firewall configuration • Open SIP ports and the RTP UDP range on your VM firewall and provider network: ◦ SIP: UDP/TCP 5060 (and TCP 5061 for TLS) ◦ RTP: UDP 10000–20000 (example range; ensure livekit-sip and LiveKit agree) • If the VM is behind NAT, set up appropriate port forwarding for these ports. • If possible, use SIP over TLS (5061) and SRTP for encrypted traffic. C. Point your SIP provider to livekit-sip • In your SIP provider dashboard, configure the SIP destination to your VM public IP (or domain) and port (5060 or 5061). • Choose authentication method: IP allowlist (recommended) or username/password. If using an IP allowlist, note the provider IPs for trunk creation. D. Add Python control-plane code to create inbound trunk & dispatch rule Create a small backend script in your existing project to register phone numbers and routing in LiveKit. Place the file at backend/sip_setup.py. File: backend/sip_setup.py • Purpose: create an inbound trunk pointing at your provider numbers and a dispatch rule that creates a room per call (prefix
call-
). Copy this into backend/sip_setup.py and update environment variables in your VM.
Copy code
import os
import asyncio
from livekit import api
from livekit.api import (
    CreateSIPInboundTrunkRequest, SIPInboundTrunkInfo,
    CreateSIPDispatchRuleRequest, SIPDispatchRule, SIPDispatchRuleIndividual,
    ListSIPInboundTrunkRequest, ListSIPDispatchRuleRequest,
)

async def setup_inbound_trunk():
    lk = api.LiveKitAPI(
        url=os.environ["LIVEKIT_URL"],
        api_key=os.environ["LIVEKIT_API_KEY"],
        api_secret=os.environ["LIVEKIT_API_SECRET"],
    )

    phone_number = os.environ["PHONE_NUMBER"]  # e.g. "+1234567890"
    provider_ip = os.environ.get("SIP_PROVIDER_IP")  # optional

    # Check existing trunks
    existing = await lk.sip.list_sip_inbound_trunk(ListSIPInboundTrunkRequest())
    trunk = None
    for t in existing.items:
        if phone_number in (t.numbers or []):
            trunk = t
            print("Found existing trunk:", trunk.sip_trunk_id)
            break

    if trunk is None:
        trunk_req = CreateSIPInboundTrunkRequest(
            trunk=SIPInboundTrunkInfo(
                name="vm-inbound-trunk",
                numbers=[phone_number],
                krisp_enabled=True,
                # allowed_addresses=[provider_ip] if provider_ip else None
            )
        )
        trunk = await lk.sip.create_sip_inbound_trunk(trunk_req)
        print("Created trunk id:", trunk.sip_trunk_id)

    # Create or find dispatch rule attached to this trunk
    existing_rules = await lk.sip.list_sip_dispatch_rule(ListSIPDispatchRuleRequest())
    rule = None
    for r in existing_rules.items:
        if trunk.sip_trunk_id in (r.trunk_ids or []):
            rule = r
            print("Found existing dispatch rule:", r.sip_dispatch_rule_id)
            break

    if rule is None:
        dispatch_req = CreateSIPDispatchRuleRequest(
            trunk_ids=[trunk.sip_trunk_id],
            rule=SIPDispatchRule(
                dispatch_rule_individual=SIPDispatchRuleIndividual(room_prefix="call")
            ),
        )
        rule = await lk.sip.create_sip_dispatch_rule(dispatch_req)
        print("Created dispatch rule id:", rule.sip_dispatch_rule_id)

    print("\nSave these values into your .env or secrets store:")
    print("SIP_INBOUND_TRUNK_ID=", trunk.sip_trunk_id)
    print("SIP_DISPATCH_RULE_ID=", rule.sip_dispatch_rule_id)

if __name__ == "__main__":
    asyncio.run(setup_inbound_trunk())
E. Environment variables (.env) — place on your VM (not in git) • LIVEKIT_URL=https//127.0.0.17880 # or your LiveKit address • LIVEKIT_API_KEY=your_api_key • LIVEKIT_API_SECRET=your_api_secret • PHONE_NUMBER=+1234567890 • SIP_PROVIDER_IP=1.2.3.4 # optional; provider’s IP for allowlist F. Agent: no code changes required for inbound • When livekit-sip receives an incoming call it will send that into LiveKit, which uses the dispatch rule to create a room (e.g., call-*) and dispatch your agent. • Ensure your agent process is running and ready to be dispatched into rooms; confirm it joins the created room and handles audio. G. Test inbound calls 1. Start livekit-sip: docker compose up -d (or systemd start). 2. Run the trunk setup: python backend/sip_setup.py 3. Configure your SIP provider to send calls to your VM public IP and port. 4. Place a call to your phone number. 5. Check: ◦ livekit-sip logs show INVITE and signaling. ◦ LiveKit creates a room named like call-id. ◦ Your agent is dispatched and joins the room. ◦ Two‑way audio works. If not, inspect RTP ports and NAT. H. Troubleshooting common issues • Provider cannot reach livekit-sip: ensure public IP/domain and SIP port are reachable; check firewall/port forwarding. • No room created: confirm livekit-sip can reach your LiveKit API (network and API keys). • No audio or one-way audio: verify RTP UDP port range is open and forwarded; confirm codecs match. • Authentication or 403/401: verify allowed provider IPs or provider credentials match what you set on the inbound trunk. If you want, I can next: • Produce a full docker-compose.yml adapted to your VM (tell me if LiveKit listens on localhost or a public address and the RTP port range you prefer). • Produce a ready-to-run sip_setup.py that matches the exact livekit-api version on your VM — paste pip freeze or requirements.txt. • Walk through the exact provider-side settings for a specific provider (e.g., Twilio or Telnyx). Which of those would you like me to do next? , with interactive elements