This document provides detailed information about the active-call configuration file (active-call.toml) parameters and configuration strategies for different calling scenarios.
- Basic Configuration
- Network Configuration
- TLS & SRTP Configuration
- Media Configuration
- Inbound Call Handler Configuration
- Recording & CDR Configuration
- Call Scenarios
# SIP service bind address
addr = "0.0.0.0"
# HTTP service address
http_addr = "0.0.0.0:8080"
# UDP port (for SIP and RTP, default 25060)
udp_port = 25060
# Enable HTTP Gzip compression (optional)
# http_gzip = true
# Log level: trace, debug, info, warn, error
log_level = "debug"
# Log file path (optional)
# log_file = "/tmp/active-call.log"
# Skip access logging for specific HTTP paths (optional)
# http_access_skip_paths = ["/health", "/metrics*"]
# Media cache path
media_cache_path = "./config/mediacache"- addr: SIP service bind address
- http_addr: HTTP service address (IP:Port)
- udp_port: UDP port for SIP signaling and RTP media
- log_level: Logging level, recommend
infoorwarnfor production - media_cache_path: Cache directory for media files (e.g., TTS audio)
If the server is behind NAT, configure the public IP:
# External IP address (for SIP signaling and media negotiation)
# If server is behind NAT, set public IP here (without port)
external_ip = "1.2.3.4"# RTP port range
rtp_start_port = 12000
rtp_end_port = 42000For WebRTC client NAT traversal:
# STUN server
[[ice_servers]]
urls = ["stun:stun.l.google.com:19302"]
# TURN server (requires authentication)
[[ice_servers]]
urls = ["turn:turn.example.com:3478"]
username = "turnuser"
credential = "turnpass"For PSTN carrier integrations (e.g. Twilio, Telnyx) that require or recommend encrypted signaling and media.
# TLS port for encrypted SIP signaling (SIPS)
# Twilio requires TLS; recommended for any production carrier connection
tls_port = 5061
tls_cert_file = "./certs/cert.pem" # Path to TLS certificate (PEM format)
tls_key_file = "./certs/key.pem" # Path to TLS private key (PEM format)When tls_port is set, active-call starts a second SIP listener on that port using TLS. The existing UDP listener on udp_port continues to run in parallel.
Generating a self-signed certificate (for testing):
mkdir -p certs
openssl req -x509 -newkey rsa:2048 -keyout certs/key.pem \
-out certs/cert.pem -days 365 -nodes \
-subj "/CN=YOUR_PUBLIC_IP_OR_DOMAIN"For production, use a CA-signed certificate (e.g. from Let's Encrypt).
# Enable SRTP for encrypted media transport (global default)
# Recommended when tls_port is active
enable_srtp = trueSRTP can also be overridden per-call via the HTTP API:
{
"callee": "sip:+18005551234@yourdomain.pstn.twilio.com",
"sip": {
"enableSrtp": true
}
}SRTP priority chain (highest to lowest):
sip.enableSrtpin the API call body — per-call overrideenable_srtpinactive-call.toml— global defaultfalse— plain RTP (fallback)
addr = "0.0.0.0"
udp_port = 5060
tls_port = 5061
tls_cert_file = "./certs/cert.pem"
tls_key_file = "./certs/key.pem"
enable_srtp = true
external_ip = "YOUR_PUBLIC_IP"
rtp_start_port = 12000
rtp_end_port = 42000See the Twilio Integration Guide for the full carrier setup walkthrough.
When using Playbooks or initiating calls via the API, if no provider is specified, Active Call will use the following defaults:
- Chinese (zh): TTS defaults to aliyun, ASR defaults to sensevoice (offline) or aliyun (online).
- English (en): TTS defaults to supertonic, ASR defaults to sensevoice (offline) or openai (online).
# SIP service bind address (corresponds to addr in basic config)
addr = "0.0.0.0"
# SIP service port (corresponds to udp_port in basic config)
udp_port = 25060Note: It's recommended not to use port 5060, as many network environments apply special handling to this port.
Active Call supports two types of SIP inbound call handling:
Forward inbound requests to an HTTP endpoint for external service decision:
[handler]
type = "webhook"
url = "http://localhost:8090/webhook"
method = "POST"Webhook Request Format:
{
"caller": "sip:alice@example.com",
"callee": "sip:bob@pbx.example.com",
"call_id": "abc123",
"from_tag": "tag1",
"to_tag": "tag2"
}Automatically route to corresponding Playbook based on caller/callee numbers:
[handler]
type = "playbook"
default = "default.md" # Optional: default playbook when no rules match
# Rule 1: US numbers calling support line
[[handler.rules]]
caller = "^\\+1\\d{10}$" # Match US number format
callee = "^sip:support@.*" # Match support line
playbook = "support.md" # Use support playbook
# Rule 2: Chinese numbers automatically use Chinese playbook
[[handler.rules]]
caller = "^\\+86\\d+" # Match Chinese numbers
playbook = "chinese.md" # Match caller only
# Rule 3: Sales line
[[handler.rules]]
callee = "^sip:sales@.*" # Match callee only
playbook = "sales.md"Rule Matching Logic:
- Rules are evaluated in order from top to bottom
- Each rule can specify
callerand/orcalleeregex patterns - Both patterns must match (omitted patterns match any value)
- First matching rule determines which playbook to use
- If no rules match and no default is set, the call is rejected
You can also quickly configure handlers via command-line parameters:
# Webhook handler
./active-call --handler https://example.com/webhook
# Playbook handler (default playbook)
./active-call --handler default.md
# Make an outgoing SIP call using a playbook
./active-call --call sip:1001@127.0.0.1 --handler greeting.md
# Set external IP and supported codecs
./active-call --external-ip 1.2.3.4 --codecs pcmu,pcma,opus[recording]
enabled = true # Enable recording
auto_start = true # Automatically start recording[callrecord]
type = "local"
root = "./config/cdr"CDR files will be saved in the specified directory, containing detailed information for each call.
Active Call supports multiple calling scenarios through different WebSocket interfaces. Here are common scenarios with their configurations and usage methods.
Use Case: Web applications, browser clients directly communicating with AI Agent.
Note: WebRTC requires a Secure Context. Ensure you are accessing your web client via HTTPS or 127.0.0.1, otherwise the browser will not enable WebRTC functionality.
# Basic configuration
http_addr = "0.0.0.0:8080"
# Configure STUN/TURN servers (for NAT traversal)
[[ice_servers]]
urls = ["stun:stun.l.google.com:19302"]
[[ice_servers]]
urls = ["turn:turn.example.com:3478"]
username = "turnuser"
credential = "turnpass"
# If behind NAT, configure external IP
external_ip = "1.2.3.4"Connect via WebSocket to the /call/webrtc endpoint:
// Establish WebSocket connection
const ws = new WebSocket('ws://localhost:8080/call/webrtc?id=session123');
// Create WebRTC PeerConnection
const pc = new RTCPeerConnection({
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' }
]
});
// Add local audio stream
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
stream.getTracks().forEach(track => pc.addTrack(track, stream));
// Create and send Offer
const offer = await pc.createOffer();
await pc.setLocalDescription(offer);
ws.send(JSON.stringify({
command: "invite",
option: {
sdp: offer.sdp,
codec: "opus",
playbook: "greeting.md"
}
}));
// Receive Answer
ws.onmessage = async (event) => {
const msg = JSON.parse(event.data);
if (msg.event === "answer") {
await pc.setRemoteDescription({
type: "answer",
sdp: msg.sdp
});
}
};- Native browser support, no plugins needed
- Low latency, suitable for real-time conversations
- Automatic NAT traversal
- Supports Opus high-quality audio codec
Use Case: Integration with enterprise PBX systems, RustPBX, FreeSWITCH, Asterisk, and traditional telephony networks.
# SIP service configuration
addr = "0.0.0.0"
udp_port = 25060
# If behind NAT, configure external IP
external_ip = "1.2.3.4"
# RTP port range
rtp_start_port = 12000
rtp_end_port = 42000Connect via WebSocket to the /call/sip endpoint:
const ws = new WebSocket('ws://localhost:8080/call/sip?id=session456');
ws.onopen = () => {
// Initiate SIP call
ws.send(JSON.stringify({
command: "invite",
option: {
caller: "sip:agent@active-call.com",
callee: "sip:1001@pbx.example.com:5060",
codec: "pcmu", // or "pcma", "g722"
playbook: "customer_service.md",
asr: {
provider: "openai",
model: "whisper-1",
language: "en-US"
},
tts: {
provider: "openai",
model: "tts-1",
voice: "alloy"
}
}
}));
};
// Handle events
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
console.log('Event:', msg.event);
if (msg.event === "answer") {
console.log('Call answered');
} else if (msg.event === "transcript") {
console.log('User said:', msg.text);
} else if (msg.event === "end") {
console.log('Call ended');
}
};RustPBX Dialplan Configuration:
# RustPBX dialplan.yml
rules:
- match: "^9999$"
actions:
- bridge: "sip:agent@active-call-server:13050"FreeSWITCH Dialplan Configuration:
<extension name="call_ai_agent">
<condition field="destination_number" expression="^9999$">
<action application="bridge" data="sofia/external/agent@active-call-server:13050"/>
</condition>
</extension>- Integration with traditional telephony networks
- Standard SIP protocol support
- Compatible with various PBX systems
- Supports G.711, G.722, and other telephony audio codecs
Use Case: Custom applications requiring full control of audio streams, or scenarios where WebRTC/SIP is not desired.
# Basic HTTP configuration is sufficient
http_addr = "0.0.0.0:8080"Connect via WebSocket to the /call endpoint:
const ws = new WebSocket('ws://localhost:8080/call?id=session789');
ws.onopen = () => {
// Start call (no SDP negotiation needed)
ws.send(JSON.stringify({
command: "start",
option: {
codec: "pcm", // or "pcma", "pcmu", "g722"
sampleRate: 16000,
playbook: "assistant.md",
vad: {
type: "silero",
samplerate: 16000,
speechPadding: 300,
silencePadding: 500
}
}
}));
};
// Send audio data
function sendAudio(audioData) {
// audioData is PCM16 format audio data (ArrayBuffer)
ws.send(audioData);
}
// Receive audio and events
ws.onmessage = (event) => {
if (event.data instanceof Blob || event.data instanceof ArrayBuffer) {
// Audio data
playAudio(event.data);
} else {
// JSON event
const msg = JSON.parse(event.data);
handleEvent(msg);
}
};WebSocket calls support the following audio formats:
- PCM: 16-bit signed, little-endian
- PCMA: G.711 A-law
- PCMU: G.711 μ-law
- G722: G.722 wideband codec
- Simplest integration method
- Full control over audio streams
- Low overhead, no RTP/RTCP protocol
- Suitable for internal system integration
Use Case: Active Call registers as a SIP endpoint to RustPBX, FreeSWITCH, Asterisk, or other PBX systems to receive inbound calls.
# SIP service configuration (use addr and udp_port from basic config)
addr = "0.0.0.0"
udp_port = 25060
# SIP registration accounts (multiple accounts supported)
[[register_users]]
server = "pbx.example.com:5060"
username = "1001"
disabled = false
[register_users.credential]
username = "1001"
password = "secret123"
realm = "pbx.example.com"
[[register_users]]
server = "pbx.example.com:5060"
username = "1002"
disabled = false
[register_users.credential]
username = "1002"
password = "secret456"
realm = "pbx.example.com"Use Playbook handler to automatically route different inbound calls:
[handler]
type = "playbook"
default = "default.md"
# Route by callee number
[[handler.rules]]
callee = "^sip:1001@.*"
playbook = "tech_support.md"
[[handler.rules]]
callee = "^sip:1002@.*"
playbook = "sales.md"
# Route by caller number
[[handler.rules]]
caller = "^sip:vip.*"
playbook = "vip_service.md"RustPBX Configuration:
# RustPBX users.yml
users:
- username: "1001"
password: "secret123"
domain: "pbx.example.com"
enabled: trueFreeSWITCH Configuration:
Create user in FreeSWITCH:
<!-- conf/directory/default/1001.xml -->
<include>
<user id="1001">
<params>
<param name="password" value="secret123"/>
</params>
</user>
</include>- Acts as standard SIP endpoint
- Can receive transfers from PBX
- Supports multiple simultaneous account registrations
- Flexible inbound routing rules
addr = "0.0.0.0"
http_addr = "0.0.0.0:8080"
log_level = "info"
media_cache_path = "./config/mediacache"
[[ice_servers]]
urls = ["stun:stun.l.google.com:19302"]
[[ice_servers]]
urls = ["turn:turn.example.com:3478"]
username = "user"
credential = "pass"
[recording]
enabled = true
auto_start = true
[callrecord]
type = "local"
root = "./config/cdr"addr = "0.0.0.0"
http_addr = "0.0.0.0:8080"
udp_port = 25060
log_level = "info"
external_ip = "203.0.113.1"
media_cache_path = "./config/mediacache"
rtp_start_port = 12000
rtp_end_port = 42000
[[ice_servers]]
urls = ["stun:stun.l.google.com:19302"]
[handler]
type = "playbook"
default = "default.md"
[[handler.rules]]
callee = "^sip:support@.*"
playbook = "support.md"
[recording]
enabled = true
auto_start = true
[callrecord]
type = "local"
root = "./config/cdr"addr = "0.0.0.0"
http_addr = "0.0.0.0:8080"
udp_port = 25060
log_level = "info"
external_ip = "203.0.113.1"
media_cache_path = "./config/mediacache"
# SIP account registration
[[register_users]]
server = "pbx.company.com:5060"
username = "ai-agent-1"
disabled = false
[register_users.credential]
username = "ai-agent-1"
password = "ComplexPassword123"
realm = "pbx.company.com"
# Webhook handler (external system determines routing)
[handler]
type = "webhook"
url = "http://crm.company.com:8090/call-routing"
method = "POST"
[recording]
enabled = true
auto_start = true
[callrecord]
type = "local"
root = "/var/recordings"In addition to configuration files, you can quickly start with command-line parameters:
# Basic usage
./active-call --conf active-call.toml
# Override HTTP address
./active-call --conf active-call.toml --http 0.0.0.0:9090
# Override SIP address
./active-call --conf active-call.toml --sip 0.0.0.0:13050
# Quick setup Webhook handler
./active-call --handler https://api.example.com/webhook
# Quick setup Playbook handler
./active-call --handler default.md
# Make an outgoing SIP call
./active-call --call sip:1001@127.0.0.1 --handler greeting.md
# Set external IP and supported codecs
./active-call --external-ip 1.2.3.4 --codecs pcmu,pcma,opus
# Combined usage
./active-call --conf active-call.toml \
--http 0.0.0.0:8080 \
--sip 0.0.0.0:13050 \
--handler https://api.example.com/webhook \
--external-ip 1.2.3.4 \
--codecs pcmu,pcma,opus- API Documentation - Detailed WebSocket API reference
- Playbook Tutorial - Playbook authoring guide
- Architecture Design - System architecture overview
- WebRTC and SIP Integration - Technical implementation details
- Browser applications → Use WebRTC (
/call/webrtc) - Telephony network integration → Use SIP (
/call/sip) - Custom apps/WeChat mini-programs → Use WebSocket (
/call) - Receiving phone calls → Configure SIP registration and inbound handler
Set external_ip to your public IP address, and open the corresponding ports on your firewall:
- HTTP/WebSocket: 8080 (or custom)
- SIP: 13050 (or custom)
- RTP: 20000-30000 (or custom range)
Deploy a load balancer (e.g., Nginx, HAProxy) in front of Active Call, noting:
- WebSocket connections need Upgrade support
- SIP and RTP use UDP protocol, requiring special handling
- Recommend using source IP hash for session affinity
- WebRTC: PCM, Opus, PCMA, PCMU, G722
- SIP: PCM, PCMA, PCMU, G722
- WebSocket: PCM, PCMA, PCMU, G722
- Set
log_level = "debug"for detailed logs - Use
log_fileto output logs to a file - Check firewall and network configuration
- Use SIP debugging tools (e.g., sngrep) to view SIP signaling