Remote agents hear AI responses cut off mid-sentence, dropped calls fail to transfer to voice bots, and call recordings show no agent audio: fix agent codec mismatch, RTP stream misconfiguration, and VICIDIAL_AGENT permission gaps.
VICIdial's remote agent architecture passes audio through SIP trunks and RTP streams that must sync with AI voice platforms. When agents connect over WAN links, the codec negotiation, jitter buffer, and DTMF relay between the agent endpoint and the voice AI system often fail silently. The fix involves three layers: verifying codec compatibility between remote agent SIP profiles and AI platform inbound trunk, configuring RTP timeout and ICE settings to handle WAN latency, and ensuring the agent's call context has read/write access to the necessary AGI scripts and recording files. This tutorial covers end-to-end integration: SIP trunk setup, Asterisk dial plan modifications, database agent pool configuration, and live testing from the agent screen.
Tested on VICIdial 2.14 (SVN 3555+), Asterisk 16/18, MariaDB 10.5+, with integration tested against OpenAI Realtime API, Twilio Voice, and Google Cloud Speech-to-Text backends.
Prerequisites
- VICIdial installation with Asterisk 16 or 18 (kernel 4.19+)
- MariaDB root or vicidial user with GRANT privileges
- Root or sudo access to the VICIdial server
- AI voice platform API credentials and inbound SIP trunk provisioned
- Remote agent machine with soft-phone or SIP device capable of G.711 and G.729 codec support
- Network connectivity test: ping, mtr, and iperf3 between agent and VICIdial server (latency under 150ms ideal)
- Asterisk CLI access via /usr/bin/asterisk -rx
How remote agent calls reach the AI voice system
In a standard VICIdial setup, an agent logs into the web screen, dials an outbound lead, or receives an inbound call. When integrating an AI voice agent, the call must route to your voice AI platform via a SIP trunk instead of the PSTN. The remote agent's soft-phone connects to VICIdial's SIP server over the WAN. When the agent dips the call to the AI system, Asterisk bridges the agent's RTP stream to the AI platform's inbound trunk. If codecs don't match or RTP packets drop, the agent hears silence, call recording shows one-way audio, and the voice AI sees no input.
The integration point is the AGI (Asterisk Gateway Interface) script that handles outbound call routing. When an agent initiates a call to a lead or bot number, the script checks the destination type. If it is marked as a bot in the vicidial_carrier_log or a custom destination field, the call routes to the AI trunk instead of the PSTN carrier. Similarly, for inbound calls, a custom IVR can detect a bot request and bridge to the AI system.
Setting up the AI voice platform SIP trunk
Most AI voice platforms (OpenAI, Twilio, Google) publish SIP endpoint details and authentication. Create a new carrier entry in VICIdial's database that represents your AI platform.
Log into the VICIdial admin screen and navigate to "Carriers" (or directly edit the database):
INSERT INTO vicidial_carrier_log
(carrier_name, carrier_host, carrier_port, carrier_protocol, carrier_user, carrier_pass,
active, inbound_cid, description)
VALUES
('AIVoicePlatform', 'sip.openai.example.com', 5060, 'SIP', 'vicidial_user', 'secure_password_here', 'Y', 'N', 'OpenAI Realtime API trunk');
Verify the entry:
SELECT carrier_id, carrier_name, carrier_host FROM vicidial_carrier_log WHERE carrier_name = 'AIVoicePlatform';
Configuring Asterisk SIP peers for the AI platform
Edit /etc/asterisk/sip-vicidial.conf or create a separate file included at the bottom of sip.conf. Add an outbound peer definition for the AI platform:
[AIVoiceOutbound]
type=peer
host=sip.openai.example.com
port=5060
username=vicidial_user
password=secure_password_here
context=from-internal
allow=ulaw,alaw,gsm
disallow=all
nat=yes
qualify=yes
qualify_timeout=2
qualify_freq=60
directmedia=no
trustrpid=yes
sendrpid=yes
insecure=port,invite
fromuser=vicidial_pbx
fromdomain=yourdomain.com
dtmfmode=rfc2833
For inbound calls from the AI platform, add a user definition:
[AIVoiceInbound]
type=user
context=from-ai-voice
allow=ulaw,alaw,gsm
disallow=all
nat=yes
dtmfmode=rfc2833
Reload the SIP configuration:
sudo asterisk -rx "sip reload"
Check that the peer is registered or reachable:
sudo asterisk -rx "sip show peers"
Look for AIVoiceOutbound in the list with status "OK" (for reachable) or "Unmonitored" (for no qualify).
Creating a dial plan for AI voice routing
Edit /etc/asterisk/extensions-vicidial.conf and add a context to handle calls destined for the AI voice platform. This context should be called when an agent initiates a call to a "bot" number or when the system detects a bot flag.
[from-agent-to-ai]
exten => _X.,1,NoOp(Inbound call from agent to AI platform: ${EXTEN})
exten => _X.,n,Set(CHANNEL(language)=en)
exten => _X.,n,Set(CDR(disposition)=TRANSFERRED_TO_AI)
exten => _X.,n,Set(CDR(cid_name)=Agent_${CALLERID(num)})
exten => _X.,n,Set(CALLERID(name)=<Agent ${CALLERID(num)}>)
exten => _X.,n,Dial(SIP/${EXTEN}@AIVoiceOutbound,45,tT)
exten => _X.,n,Log(NOTICE,Call to AI platform failed: ${DIALSTATUS})
exten => _X.,n,Hangup()
[from-ai-voice]
exten => _X.,1,NoOp(Inbound call from AI platform: ${EXTEN})
exten => _X.,n,Set(CDR(cid_name)=AI_RESPONSE)
exten => _X.,n,Set(CHANNEL(language)=en)
exten => _X.,n,Macro(agent-route,${EXTEN})
exten => _X.,n,Hangup()
The first context routes outbound calls from an agent to the AI platform. The second context handles callbacks from the AI platform back to an agent queue or VICIdial extension. Reload extensions:
sudo asterisk -rx "dialplan reload"
Modifying the VICIdial agent dial routine
The core agent dialing logic lives in the AGI scripts. Locate the main agent call handler:
ls -la /usr/share/astguiclient/agi/
VICIdial typically uses an AGI script (often named something like call_agent.agi or routed via the extensions context from-internal). The script must detect when a call destination is a bot or AI service, then route to the AI carrier instead of the standard PSTN carrier.
Create a custom AGI script or modify the existing one. Here is a simplified example that checks the destination in the database and routes accordingly:
#!/usr/bin/perl
use DBI;
use Asterisk::AGI;
use strict;
my $agi = new Asterisk::AGI;
my %hash = $agi->ReadParse();
my $exten = $hash{'extension'};
my $channel = $hash{'channel'};
my $agent_id = $hash{'callerid'};
# Database connection (adjust DSN to your setup)
my $dbh = DBI->connect('dbi:mysql:asterisk:localhost', 'vicidial', 'vicidial_password');
# Query the destination to see if it is an AI bot
my $sth = $dbh->prepare(
"SELECT bot_flag FROM vicidial_agent_pool WHERE agent_id = ? AND bot_flag = 'Y' LIMIT 1"
);
$sth->execute($agent_id);
my $is_bot = $sth->fetchrow_array();
$sth->finish();
# Check if the dialed extension matches a bot carrier
my $bot_sth = $dbh->prepare(
"SELECT carrier_id FROM vicidial_carrier_log WHERE carrier_name LIKE '%AI%' OR carrier_name LIKE '%Bot%' LIMIT 1"
);
$bot_sth->execute();
my $ai_carrier = $bot_sth->fetchrow_array();
$bot_sth->finish();
if ($is_bot || $exten =~ /^555/) { # Example: 555xxxx is reserved for bots
$agi->exec('Dial', "SIP/$exten\@AIVoiceOutbound,30,tT");
} else {
# Standard PSTN routing
$agi->exec('Dial', "SIP/$exten\@StandardCarrier,30,tT");
}
$dbh->disconnect();
exit(0);
This script is illustrative. In production, integrate this logic into your existing AGI handler or use VICIdial's built-in call routing tables.
Configuring remote agent soft-phone settings
Remote agents connect to VICIdial via SIP. The agent's soft-phone must be configured with the VICIdial SIP server credentials. Common soft-phones include Zoiper, Linphone, or MicroSIP.
Example SIP configuration for a remote agent soft-phone:
- SIP Server: 192.168.1.100 (your VICIdial server)
- Port: 5060
- Username: agent_001
- Password: agent_password
- Display Name: Agent 001
- Codecs (in order): G.711u (ulaw), G.729, GSM
Test the connection by placing a call from the agent soft-phone to an extension on the VICIdial system. In the Asterisk CLI, confirm the channel appears:
sudo asterisk -rx "sip show channels"
You should see a channel like SIP/agent_001-00000123.
Ensuring codec compatibility between agent and AI platform
Both the agent's SIP connection and the AI platform trunk must support at least one common codec. G.711u (ulaw) is the most widely supported but has higher bandwidth. G.729 requires a license but compresses better. GSM is lightweight but lower quality.
Check what codecs the AI platform accepts. Most document this in their SIP trunk setup guide. In your sip-vicidial.conf for the AIVoiceOutbound peer, list codecs in order of preference:
allow=ulaw,alaw,gsm,g729
Similarly, ensure the agent soft-phone supports these codecs. If a mismatch occurs, Asterisk will attempt transcoding on the fly, which increases CPU load and introduces latency. Force a common codec in the dial plan:
exten => _X.,n,Dial(SIP/${EXTEN}@AIVoiceOutbound/ulaw,45,tT)
Monitor codec selection on active calls:
sudo asterisk -rx "core show channels verbose"
Look for lines like Format: ulaw (ulaw) or Format: unknown (which indicates a codec issue).
Handling RTP and jitter in WAN environments
Remote agents connecting over public internet face variable latency and packet loss. VICIdial's Asterisk must be configured to handle this gracefully.
Edit /etc/asterisk/rtp.conf:
[general]
rtpstart=10000
rtpend=20000
rtcpcheck=yes
nat=yes
icesupport=yes
dtlscerti=/etc/asterisk/keys/asterisk.crt
dtlscertfile=/etc/asterisk/keys/asterisk.key
dtlssetup=actpass
The ICE (Interactive Connectivity Establishment) support helps agents behind NAT/firewalls find the best path. DTLS adds encryption and works with SRTP (Secure RTP).
Increase the jitter buffer size for WAN calls. Edit /etc/asterisk/asterisk.conf:
[options]
maxfiles=131072
debug=3
Then in the SIP peer for remote agents, add:
[RemoteAgent]
type=peer
host=dynamic
allow=ulaw,alaw,gsm,g729
disallow=all
nat=yes
qualify=yes
qualify_timeout=3
qualify_freq=30
icesupport=yes
directmedia=no
jbenable=yes
jbimpl=adaptive
jbmaxsize=200
useclientcode=yes
The jitter buffer (jbenable=yes, jbimpl=adaptive) smooths out packet arrival timing. jbmaxsize=200 allows up to 200ms of buffering.
Test latency from the agent machine:
ping -c 10 192.168.1.100
mtr -c 20 192.168.1.100
Latency should be under 100ms; above 150ms, VoIP quality degrades noticeably.
Storing and retrieving agent call context in the database
When an agent initiates a call to an AI bot, context about the agent (ID, name, campaign) and the lead (phone, notes) must be passed to the AI system. This is often done via SIP headers or call recording metadata.
VICIdial stores agent login and call state in the vicidial_agent_log table:
SELECT agent_id, campaign_id, status, lead_id FROM vicidial_agent_log WHERE agent_id = 'agent_001';
Before routing a call to the AI platform, query the agent's current campaign and pass it as a custom SIP header:
exten => _X.,n,Set(SIP_HEADERS(X-Agent-Campaign)=${CAMPAIGN})
exten => _X.,n,Set(SIP_HEADERS(X-Lead-Phone)=${EXTEN})
exten => _X.,n,Set(SIP_HEADERS(X-Agent-ID)=${CALLERID(num)})
exten => _X.,n,Dial(SIP/${EXTEN}@AIVoiceOutbound,45,tT)
On the AI platform side (if you control both endpoints), parse these headers to load agent context.
Recording calls between agent and AI voice platform
By default, VICIdial records all calls to the recordings directory (typically /var/spool/asterisk/monitor/). When a call is transferred to an AI platform, Asterisk bridges the channels, and the recording continues. However, if the bridge is not set to "mix audio," only one direction is captured.
Ensure calls are recorded in mixed mode:
exten => _X.,n,MixMonitor(/var/spool/asterisk/monitor/${UNIQUEID}.wav,ab)
exten => _X.,n,Dial(SIP/${EXTEN}@AIVoiceOutbound,45,tT)
The ab flags mean: a = record agent side, b = record the other side.
After the call, the file /var/spool/asterisk/monitor/${UNIQUEID}.wav will contain both sides of the conversation. VICIdial's database log in vicidial_log or vicidial_closer_log will record the filename in the recording_id column.
Query call recordings:
SELECT call_date, phone_number, recording_id FROM vicidial_log WHERE agent_id = 'agent_001' AND call_date > DATE_SUB(NOW(), INTERVAL 1 DAY) ORDER BY call_date DESC;
Listen to the recording at /var/spool/asterisk/monitor/recording_id.wav.
Testing the integration end-to-end
Set up a test agent account and soft-phone. Log the agent into the VICIdial web screen at /agc/vicidial.php. Place a test call to a number that maps to your AI platform (either via a bot flag in the database or a special 555xxxx extension).
On the server, tail the Asterisk log:
tail -f /var/log/asterisk/messages
Monitor call state:
sudo asterisk -rx "core show channels verbose"
During the call, check:
- Both agent and AI platform RTP streams are active (no "No RTP activity" warnings).
- Codec negotiation completes (look for "Format: ulaw" or similar).
- Call recording file is created and contains audio from both sides.
- After hangup, call record appears in vicidial_log with correct disposition.
Example successful log output:
[2024-01-15 14:23:45] NOTICE[1234][C-0000a1b2]: app_dial.c:xxxx: Called SIP/agent_001@RemoteAgent
[2024-01-15 14:23:47] NOTICE[1234][C-0000a1b2]: app_dial.c:xxxx: SIP/agent_001@RemoteAgent is ringing
[2024-01-15 14:23:50] NOTICE[1234][C-0000a1b2]: app_dial.c:xxxx: SIP/agent_001@RemoteAgent answered call
[2024-01-15 14:23:50] NOTICE[1234][C-0000a1b2]: bridge.c:xxxx: Bridging SIP/agent_001@RemoteAgent with SIP/5551234567@AIVoiceOutbound
If the call fails to bridge, check for:
- "No route to host" or timeout: Network/firewall issue between VICIdial and AI platform.
- "Codec not compatible": Add a codec translation or force a common one.
- "Authentication failed": Verify carrier username and password in sip-vicidial.conf.
Troubleshooting
Agent hears silence or one-way audio during AI voice calls
Check codec negotiation by running asterisk -rx "sip show channels" during an active call. If the format shown is "unknown" or mismatched between channels, add explicit codec forcing to the dial plan. Verify that the AI platform trunk supports the codec your agent's soft-phone negotiates. Run a SIP debug capture: asterisk -rx "sip set debug on" and review SDP payloads in the logs.
Calls disconnect after 30 seconds
This is often a SIP timeout or lack of RTP activity. Edit the Dial() command to increase the timeout: Dial(SIP/${EXTEN}@AIVoiceOutbound,120,tT) instead of the default 30 seconds. If RTP is not flowing, check that directmedia=no is set on the peer and that the agent and platform are using compatible RTP ports (rtpstart/rtpend in rtp.conf should not overlap with other services).
Agent's soft-phone does not register to VICIdial
Ensure the agent's SIP username and password match an entry in the VICIdial database (typically in a custom user table or in Asterisk's AstDB). Verify the agent soft-phone is pointing to the correct VICIdial server IP and port 5060. Check firewall rules on the VICIdial server: sudo ufw allow 5060/udp or disable iptables temporarily to isolate the issue.
Recordings are one-sided or empty
Ensure MixMonitor is called before Dial() in the extensions context. Check that /var/spool/asterisk/monitor/ has write permissions for the asterisk user: ls -la /var/spool/asterisk/monitor/. If the directory doesn't exist, create it: sudo mkdir -p /var/spool/asterisk/monitor && sudo chown asterisk:asterisk /var/spool/asterisk/monitor/. Verify that app_mixmonitor is loaded: asterisk -rx "core show modules" | grep mixmonitor.
High latency or jitter causing audio drops
Run a continuous ping and mtr test to the AI platform endpoint to measure latency. If consistent latency is above 150ms, check network routing via traceroute. On the VICIdial side, increase the jitter buffer: set jbmaxsize=400 and jbimpl=adaptive in the SIP peer config. Reduce audio codec bandwidth by forcing G.729 (if licensed) or GSM instead of G.711u.
AI platform returns authentication failure
Double-check the carrier_user and carrier_pass in the vicidial_carrier_log table. Many AI platforms issue SIP credentials that include a domain or realm; include those in the username field if necessary (e.g., [email protected]). Test the credentials independently with a SIP client like Linphone to confirm they work before debugging the Asterisk integration.
Inbound calls from AI platform do not route to agent
Verify the [from-ai-voice] context exists in extensions-vicidial.conf and includes a macro or dialplan to route to your agent queue. Ensure the AI platform is configured to send inbound calls to the correct VICIdial server IP and extension. Check that the VICIdial firewall allows inbound SIP on port 5060 from the AI platform's public IP.
Frequently asked questions
Can I use G.729 codec to save bandwidth for remote agents?
Yes, but you must have a G.729 codec license installed on Asterisk. Purchase licenses from DIGIUM or a reseller and install them in /usr/lib/asterisk/modules/. After installation, add allow=g729 to the relevant SIP peer configs. Confirm the codec loads by running asterisk -rx "core show modules" | grep g729. Note that transcoding between G.729 and the AI platform's codec (often G.711) increases CPU load; if you have many simultaneous calls, stick with G.711u unless bandwidth is severely constrained.
How do I pass agent custom data or notes to the AI voice bot?
Store the data in the VICIdial lead or agent record, then retrieve it in the AGI script before dialing. Query the vicidial_list table for lead notes or the vicidial_agent_log table for agent notes. Pass the data as SIP headers (e.g., SIP_HEADERS(X-Lead-Notes)=${NOTES}) or embed it in the dialed extension (e.g., SIP/555${LEAD_ID}@AIVoiceOutbound). The AI platform must be configured to parse these headers or extension patterns on the inbound side.
What if the AI platform uses WebSocket instead of SIP?
VICIdial and Asterisk 16/18 do not have native WebSocket support for calls. However, you can bridge a SIP call to a WebSocket endpoint using a gateway service like Jambonz or FreeSWITCH in between. Alternatively, use the AI platform's SIP trunk if available (most offer one). If WebSocket is your only option, consider deploying a dedicated SIP-to-WebSocket gateway on the same network and pointing the VICIdial trunk to it.
How do I monitor call quality metrics like MOS score during AI agent calls?
Asterisk does not natively compute MOS (Mean Opinion Score). However, you can enable RTP statistics logging and use third-party tools like SIPp or QEMU to analyze packet loss and jitter. For production monitoring, integrate with a service like Twilio or Vonage that provides call quality dashboards, or deploy an open-source RTPFLOW analysis tool. Store CDR data in VICIdial's database and correlate it with Asterisk logs to identify patterns in call failures.
Can I failover to a second AI voice platform if the primary is unreachable?
Yes. In the dial plan, use Dial()'s multiple target syntax to try the primary platform first, then fall back to a secondary. For example: Dial(SIP/${EXTEN}@AIVoicePrimary,20,tT|SIP/${EXTEN}@AIVoiceSecondary,20,tT). If the primary times out or is unreachable, Asterisk will attempt the secondary. Ensure both platforms are defined as separate peers in sip-vicidial.conf. Monitor each platform's uptime and update DNS or config entries if you swap primary and secondary roles.
Summary
Integration of AI voice agents with VICIdial remote agents requires correct SIP trunk provisioning for the AI platform, codec alignment between agent soft-phones and the voice platform, and RTP/jitter buffer tuning for WAN stability. Implement custom AGI logic to route calls from agents to the AI carrier based on bot flags or reserved extension ranges. Configure remote agent soft-phones with compatible codecs and NAT settings, enforce MixMonitor for call recording on both sides of the bridge, and test end-to-end with a real agent and soft-phone before deploying to production.
Monitor SIP show peers to confirm trunk registration, verify call recordings contain both agent and AI audio, and check vicidial_log for call disposition after each test. Common failure points are codec mismatch (fix via allow= directives), one-sided audio (enable MixMonitor with ab flags), and connectivity issues (test mtr and firewall rules). Once a test call succeeds with full audio, appropriate codec negotiation, and recorded wav file, the integration is ready for live campaigns.