Diagnose packet loss, jitter, and latency causing one-way audio and dropped calls using Smokeping graphs and RTCP statistics parsed from Asterisk logs.
VoIP call quality degrades when latency exceeds 150ms, jitter spikes above 30ms, or packet loss hits 1% or higher. Smokeping detects these conditions in real time by sending ICMP probes to carriers and gateways; RTCP (Real-time Transport Control Protocol) statistics logged by Asterisk show the actual audio path performance on each call. Together, they isolate whether the problem is network-wide, carrier-specific, or codec-related. Fix the cause by tuning SIP timeouts, adjusting Asterisk jitter buffer settings, or switching carriers.
Tested on ViciDial 2.14 (SVN 3555+), Asterisk 16/18, MariaDB 10.5+, Smokeping 2.6.11+, and CentOS 7.x.
Prerequisites
- Root or sudo access to Asterisk/ViciDial server.
- SNMP installed and running (for Smokeping probes).
- Asterisk compiled with RTCP stats enabled (default in most packages).
- Network access to carrier gateways and upstream routers.
- MariaDB client access to the asterisk database.
- Basic knowledge of Asterisk CLI commands and SIP configuration.
- ViciDial web admin panel installed at /vicidial/admin.php.
Why does call quality fail on some carriers but not others?
Each carrier's SIP trunk has its own path through the internet: different routers, different buffer depths, different packet scheduling. If your ISP routes calls to Carrier A via a congested edge, but Carrier B through a cleaner path, one will have jitter and loss while the other is clean. Smokeping measures ICMP latency to each gateway; RTCP stats measure actual RTP audio packets on that carrier's calls. When the two disagree, the problem is SIP signaling or call routing, not the network path itself.
Smokeping setup for VoIP monitoring
Installing and configuring Smokeping
Install Smokeping on a dedicated monitoring host or the Asterisk server itself (if CPU headroom allows).
yum install smokeping fping -y
systemctl enable smokeping
systemctl start smokeping
Edit the main Smokeping config at /etc/smokeping/config:
*** Targets ***
probe = FPing
title = VoIP Carrier Gateways
+ Carriers
menu = Carriers
title = Upstream SIP Carriers
++ Carrier_A
menu = Carrier A
title = Carrier A SIP Gateway
host = 203.0.113.45
+ Carrier_B
menu = Carrier B
title = Carrier B SIP Gateway
host = 198.51.100.22
+ Internal
menu = Internal
title = Internal Gateways and Interfaces
++ PBX_Main
menu = PBX Main
title = Main Asterisk Server
host = 192.168.1.10
++ WAN_Interface
menu = WAN
title = WAN Uplink
host = 192.0.2.1
Smokeping sends ICMP pings every 60 seconds by default. Set per-target intervals shorter for critical carriers:
++ Carrier_A
menu = Carrier A
title = Carrier A SIP Gateway
host = 203.0.113.45
step = 30
pings = 20
Enable cgi and web serving:
chown smokeping:smokeping /var/lib/smokeping/
chown smokeping:smokeping /var/cache/smokeping/
systemctl restart smokeping
Access the dashboard at http://your-server/smokeping/ (may require Apache alias configuration).
Reading Smokeping graphs
The Smokeping graph for each target shows five metrics:
- Green line (median latency): actual round-trip time in milliseconds.
- Blue area (50th percentile band): half of your probes fall here.
- Red area (95th percentile band): outlier probes (bad luck, retransmits).
- Gray zones at the bottom: packet loss shown as gaps or light fill.
- Spike up: jitter or a delayed single probe.
If a carrier's median latency creeps from 45ms to 120ms over an hour, and packet loss appears as gray bands, you have a congestion event. If the red band widens but median stays stable, you have jitter without sustained loss.
Baseline your carriers under normal call load. Morning, midday, and evening should each show similar latency. If evening spikes 50ms higher than morning, your ISP or carrier oversubscribes evenings.
RTCP statistics: what they tell you
RTCP packets flow in parallel with RTP audio. Every few seconds, each end sends stats: bytes sent, packets sent, lost packets, jitter in milliseconds, and round-trip delay. Asterisk logs these in /var/log/asterisk/messages under the RTCP tag.
Enabling RTCP logging in Asterisk
Edit /etc/asterisk/sip.conf or sip-vicidial.conf:
[general]
rtcpinterval=5000
rtcpunit=ms
Then restart Asterisk:
asterisk -rx "module reload chan_sip.so"
Verify RTCP is flowing on an active call:
asterisk -rx "sip show channels verbose"
You will see lines like:
SIP/carrier-a-00000c7a (to caller) (format=ULAW)
Relaying RTP to SIP/agent-00000c79 (format=ULAW)
RTCP sent to: 203.0.113.45:16889
RTCP received from: 203.0.113.45:16888
Parsing RTCP from logs
After a call ends, grep the call ID in /var/log/asterisk/messages:
grep "RTCP" /var/log/asterisk/messages | tail -50
A typical RTCP log line:
[2024-01-15 14:22:33] VERBOSE[12345][C-0000c7a]: chan_sip.c: RTCP SR (Sender Report) from 203.0.113.45:16888: ssrc=3456789 packets=1245 octets=198400 ntp=e0d1f52a.8b2c3d41 ts=987654 jitter=8.5 loss=0 delay=45
Extract and store these metrics in a script. A practical approach: parse the CDR and pull RTCP stats into a custom table.
Create a VoIP quality metrics table
In the asterisk database, add a table for call-level RTCP stats:
CREATE TABLE `voip_call_quality` (
`id` int AUTO_INCREMENT PRIMARY KEY,
`call_date` datetime NOT NULL,
`call_id` varchar(128),
`carrier` varchar(64),
`src_ip` varchar(45),
`dst_ip` varchar(45),
`jitter_ms` float,
`packet_loss_pct` float,
`latency_ms` int,
`codec` varchar(16),
`direction` enum('inbound','outbound'),
`call_status` varchar(32),
KEY `call_date_idx` (`call_date`),
KEY `carrier_idx` (`carrier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Write a PHP script to parse Asterisk logs and insert rows. Run it hourly via cron:
<?php
// /usr/local/bin/parse_rtcp.php
$pdo = new PDO('mysql:host=localhost;dbname=asterisk', 'root', 'password');
$logfile = '/var/log/asterisk/messages';
$lines = file($logfile);
foreach ($lines as $line) {
if (strpos($line, 'RTCP') === false) continue;
// Extract fields using regex
if (preg_match('/\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\].*RTCP.*from\s([\d\.]+).*jitter=([\d.]+)\s.*loss=([\d]+)\s.*delay=(\d+)/', $line, $m)) {
$call_date = $m[1];
$src_ip = $m[2];
$jitter = $m[3];
$loss = $m[4];
$delay = $m[5];
$stmt = $pdo->prepare('INSERT INTO voip_call_quality (call_date, src_ip, jitter_ms, packet_loss_pct, latency_ms) VALUES (?, ?, ?, ?, ?)');
$stmt->execute([$call_date, $src_ip, $jitter, $loss, $delay]);
}
}
?>
Query the table to spot trends:
SELECT carrier, AVG(jitter_ms) as avg_jitter, AVG(packet_loss_pct) as avg_loss, AVG(latency_ms) as avg_latency, COUNT(*) as call_count
FROM voip_call_quality
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY carrier
ORDER BY avg_loss DESC;
High loss or jitter on a specific carrier shows up immediately.
Common call quality problems and fixes
One-way audio: caller hears agent, agent hears nothing
One-way audio almost always means the RTP stream from agent to caller is blocked or misrouted. Check:
- SIP ALG (Application Layer Gateway) is enabled on your router. NAT gateways sometimes "help" by rewriting SIP headers, which breaks RTP routing. Disable SIP ALG in your router's advanced settings, or add a static NAT rule:
Router: Port Forward SIP traffic (UDP 5060, 5061) to Asterisk IP
Do NOT enable SIP Proxy or SIP ALG
- Agent's IP is different from ViciDial's configured IP. If your agent is behind a different NAT or carrier than the main Asterisk server, SIP can establish but RTP gets stuck. In /etc/asterisk/sip-vicidial.conf, set:
[general]
externip = 203.0.113.10
externhost = pbx.yourdomain.com
Then reload:
asterisk -rx "sip reload"
- Firewall blocking RTP return traffic (ephemeral ports). RTP uses high-numbered UDP ports (10000-20000 by default). Allow all outbound UDP from your Asterisk server:
# On CentOS 7 with firewalld
firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.1.0/24 protocol value=udp port protocol=udp port=10000-20000 accept'
firewall-cmd --reload
- Jitter buffer misconfigured. If jitter on the agent side exceeds 50ms, the jitter buffer may be filling then draining, causing audio drop. In extensions-vicidial.conf, find the agent channel definition and set:
[agent-channel]
same => n,Set(JITTERBUFFER(adaptive)=yes)
same => n,Set(JITTERBUFFER(maxsize)=200)
200ms is the max buffer; adaptive mode expands and contracts based on network conditions.
One-way audio on specific carriers only
Your carrier's SIP server may not be sending RTP back on the port you sent from. This is a carrier misconfiguration, not your network.
Check your RTCP logs for that carrier. If you see jitter and loss on one leg but not the other, the issue is asymmetric routing: outbound RTP takes one path, inbound takes another. Carriers often load-balance across multiple gateways.
Ask the carrier to:
- Pin your SIP session to a single media gateway (no load balancing of RTP).
- Confirm their firewall allows your public IP to send RTP to any port they assign (not just 5060).
- Provide a static IP or whitelist for your SIP trunk.
Meanwhile, check your trunk settings in /etc/asterisk/sip-vicidial.conf:
[carrier-a]
type=peer
host=203.0.113.45
fromuser=your_account_id
secret=your_password
disallow=all
allow=ulaw
dtmfmode=rfc2833
natmode=yes
qualify=200
Set natmode=yes to send keepalives and qualify=200 to test each peer every 200ms. Restart SIP:
asterisk -rx "sip reload"
High jitter causes choppy or robotic audio
Jitter of 20-30ms is normal on internet circuits. Above 50ms, audio quality degrades noticeably. Causes:
- Congestion on your ISP link (Smokeping will show rising latency).
- Carrier overload (check RTCP logs for loss; Smokeping to carrier gateway will show red bands).
- Competing traffic (torrent, backup, video) sharing your uplink.
Fixes:
- Enable QoS (Quality of Service) on your router. Prioritize SIP and RTP traffic:
Router -> QoS or Traffic Shaping -> UDP port 5060 (SIP) = High Priority
-> UDP port 10000-20000 (RTP) = High Priority
-> Everything else = Low Priority
- Reduce jitter buffer in Asterisk. Counterintuitive, but a large buffer hides jitter initially then delivers a burst of late packets, causing audio dropout. Set to 50ms max:
same => n,Set(JITTERBUFFER(maxsize)=50)
- Switch to G.729 codec if on metered bandwidth. G.729 uses 8 kbps vs ULAW's 64 kbps. Fewer packets means less jitter. But check your licensing: G.729 requires a per-channel license. In sip-vicidial.conf:
[general]
disallow=all
allow=g729
allow=ulaw
- Check if Smokeping shows your ISP uplink is congested. If Smokeping to your WAN gateway shows rising latency and packet loss in evenings, you need more bandwidth. Contact your ISP.
Packet loss causes dropped words or silent gaps
Packet loss of 0.5% is noticeable; 1% or higher makes calls unusable. Causes:
- Carrier network issue (Smokeping to their gateway shows loss, RTCP confirms it).
- Your ISP oversubscribed (Smokeping shows loss to your upstream router).
- Firewall or IDS dropping packets (less common, but check syslog for drops).
Fixes:
- Verify loss is not just on one codec. Query your quality table:
SELECT codec, AVG(packet_loss_pct) as avg_loss
FROM voip_call_quality
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY codec;
If loss is high on ULAW but low on G.729, the issue may be RTP packet size or MTU mismatch, not the network.
- Check MTU size. SIP and RTP packets may be fragmented if your MTU is below 1500 bytes. Confirm:
ip link show
# Look for "mtu 1500"
If MTU is below 1500, increase it:
ip link set dev eth0 mtu 1500
Make persistent in /etc/sysconfig/network-scripts/ifcfg-eth0:
MTU=1500
Use FEC (Forward Error Correction) on critical carriers. Some carriers offer FEC, which adds redundancy so a single lost packet can be recovered. This increases bandwidth but improves quality on lossy links. Ask your carrier if available.
Switch carriers. If Smokeping shows your ISP or the carrier has persistent loss, and both confirm the SLA is being met (they contractually allow that loss), you need a different path. Add a second carrier with a different ISP and load-balance calls between them.
Calls drop after 30 seconds
Asterisk's default SIP session timer is 1800 seconds (30 minutes), but if a SIP proxy or NAT device between you and the carrier times out after 30 seconds, the call will drop. Check your carrier's SIP signaling logs first. Then, in sip-vicidial.conf, enable session timers:
[general]
session_timers=accept
session_expires=600
min_se=90
This sends a RTCP keepalive every 90 seconds. Restart:
asterisk -rx "sip reload"
If drops persist, the issue is likely SIP signaling loss (high latency on SIP requests), not the RTP stream. Query your CDR for calls with short duration:
SELECT caller_id, called_number, LENGTH_IN_SEC, call_date
FROM vicidial_log
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 24 HOUR)
AND LENGTH_IN_SEC < 35
AND LENGTH_IN_SEC > 25
ORDER BY call_date DESC
LIMIT 20;
If most of your short calls are exactly 30 seconds, a NAT timeout is happening. Add a SIP registration keepalive:
[general]
register => your_account_id:[email protected]/your_account_id
[carrier-a]
type=peer
host=203.0.113.45
fromuser=your_account_id
secret=your_password
qualify=60
The qualify=60 sends a SIP OPTIONS ping every 60 seconds to keep the NAT binding alive.
Correlating Smokeping and RTCP data
The most powerful diagnostic is overlaying Smokeping and RTCP metrics on the same timeline.
Write a script to pull both datasets for a 24-hour window:
#!/bin/bash
# /usr/local/bin/voip_quality_report.sh
CARRIER=${1:-all}
HOURS=${2:-24}
echo "=== SMOKEPING LATENCY (avg, min, max) ==="
sqlite3 /var/lib/smokeping/data/smokeping.db << EOF
SELECT datetime(timestamp,'unixepoch') as time, median, loss
FROM smokeping_data
WHERE hostname LIKE '%$CARRIER%'
AND timestamp > strftime('%s', 'now', '-$HOURS hours')
ORDER BY timestamp;
EOF
echo ""
echo "=== RTCP METRICS (by carrier) ==="
mysql -u root -p asterisk << EOF
SELECT DATE_FORMAT(call_date, '%Y-%m-%d %H:00') as hour,
carrier,
AVG(jitter_ms) as jitter,
AVG(packet_loss_pct) as loss,
AVG(latency_ms) as latency,
COUNT(*) as calls
FROM voip_call_quality
WHERE call_date >= DATE_SUB(NOW(), INTERVAL $HOURS HOUR)
AND (carrier LIKE '%$CARRIER%' OR '$CARRIER' = 'all')
GROUP BY DATE_FORMAT(call_date, '%Y-%m-%d %H:%i'), carrier
ORDER BY call_date DESC;
EOF
Run it:
./voip_quality_report.sh carrier-a 24
Look for time windows where Smokeping shows rising latency and RTCP shows rising jitter and loss. If they correlate, the problem is the network path. If Smokeping is clean but RTCP is poor, the issue is codec, SIP signaling, or internal Asterisk processing.
Asterisk CLI diagnostics for call quality
While a call is active, pull real-time RTP stats:
asterisk -rx "sip show channels verbose"
Output:
SIP/carrier-a-00000c7a (to 5551234567)
Codecs: (ulaw|alaw|g729)
RTP Stream: 192.168.1.10:12345 <-> 203.0.113.45:16888
Jitter buffer: adaptive, max 200ms
Last RTP: 48ms ago
Check for RTP gaps (Last RTP > 2 seconds means audio is frozen):
for i in {1..10}; do asterisk -rx "sip show channels" | grep -E "RTP|Last RTP"; sleep 1; done
If Last RTP keeps incrementing, audio is not flowing. Check firewall and NAT.
Troubleshooting
Smokeping shows loss but RTCP shows none
Smokeping sends ICMP (ping) traffic; RTP is UDP. Your firewall or router may allow RTP but rate-limit ICMP. ICMP loss is not proof of RTP loss. But if Smokeping shows sustained ICMP loss (>1% for >10 minutes), your ISP uplink is congested and RTP will suffer next.
Increase Smokeping pings per cycle to get more accurate loss:
++ Carrier_A
pings = 50
And confirm with MTR (My Traceroute) for a sustained, detailed view:
mtr -c 1000 203.0.113.45 > mtr_report.txt
MTR combines ping and traceroute. If you see loss or latency spike at a specific hop (ASN or ISP), report it to your carrier.
RTCP shows jitter but audio is clear
Jitter measurement in RTCP is instantaneous. A spike to 80ms on one packet does not mean audio is bad. Look for sustained jitter >50ms over hundreds of packets. Query your quality table by minute:
SELECT
DATE_FORMAT(call_date, '%Y-%m-%d %H:%i') as minute,
AVG(jitter_ms) as avg_jitter,
MAX(jitter_ms) as max_jitter,
COUNT(*) as samples
FROM voip_call_quality
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
GROUP BY minute
HAVING avg_jitter > 40 OR max_jitter > 100;
If spikes are rare and brief, your jitter buffer is absorbing them. If sustained, increase buffer size or reduce codec bitrate.
Smokeping has no data
Smokeping is running but the graphs are empty.
Check the Smokeping daemon log:
tail -100 /var/log/smokeping/smokeping.log
Common issues:
- fping binary is missing or broken. Reinstall:
yum reinstall fping
ls -la /usr/sbin/fping
- Smokeping has no write permission. Fix:
chown -R smokeping:smokeping /var/lib/smokeping/
chmod 755 /var/lib/smokeping/
- Target host is unreachable. Verify you can ping it manually:
ping -c 5 203.0.113.45
If packets are blocked, add the target to your firewall whitelist.
ViciDial shows calls as DEAD but RTCP shows no loss
"DEAD" status in the ViciDial log usually means the agent hung up or the carrier disconnected the call, not that the call failed mid-stream.
Check the call disposition in /vicidial/admin.php (Reports -> Inbound/Outbound Call Log) or query directly:
SELECT call_date, caller_id, called_number, status, LENGTH_IN_SEC, disconnect_reason
FROM vicidial_log
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
AND status = 'DEAD'
LIMIT 10;
If disconnect_reason is empty or "normal", the agent hung up or the call ended naturally. If it contains "SIP/403" or "SIP/486", the carrier rejected the call. If "timeout", SIP signaling stalled.
Filter for actual failure calls (short duration + SIP error):
SELECT call_date, caller_id, status, disconnect_reason
FROM vicidial_log
WHERE call_date >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
AND LENGTH_IN_SEC < 5
AND disconnect_reason LIKE 'SIP%'
ORDER BY call_date DESC;
Frequently asked questions
Why does one agent hear perfect audio while another has jitter on the same call?
Jitter is primarily a function of the path from the remote party back to your agent. If two agents are in the same office but receiving calls on different carriers, or from different geographic regions, their RTP paths will differ. The path from New York to Los Angeles is not the same as New York to London. Check RTCP stats per agent and per carrier; you may find that Agent A (in LA) has low jitter from LA-based callers but high jitter from international calls.
Should I prioritize Smokeping latency numbers or RTCP jitter numbers?
Prioritize RTCP jitter because it reflects actual audio packet timing. Smokeping shows the baseline path; RTCP shows how audio packets are actually behaving. If Smokeping is clean but RTCP is noisy, the issue is call-specific: codec, SIP processing, or call routing. If both are high, the network path itself is the problem.
Is 50ms latency acceptable for VoIP?
Yes. The ITU-T G.114 recommendation allows up to 150ms one-way latency with no perceptible impact. Below 50ms, users notice no delay. Between 50-150ms, the delay is noticeable but tolerable. Above 150ms, calls feel like a satellite conversation (long pause before response). Your baseline latency should be stable and predictable; random jitter is more harmful than high latency.
Can I reduce jitter by switching from SIP to IAX2?
IAX2 (Inter-Asterisk eXchange) is a different VoIP protocol that may have lower jitter on certain network paths because it is more efficient than SIP+RTP. However, carrier support is rare. Most carriers only offer SIP trunks. If your carrier supports IAX2, test it against your current SIP trunk on the same calls. Use the same monitoring: Smokeping and RTCP stats.
What packet loss is acceptable?
Zero is ideal. Packet loss of 0.1-0.3% is generally not noticeable to the human ear on a 20ms-sample voice codec. Above 0.5%, most callers notice some clipping or words dropping out. Above 1%, the call is poor. If your RTCP data shows >0.5% loss on any carrier, contact the carrier to investigate or switch to a different carrier/path.
Summary
Deploy Smokeping to continuously monitor latency, jitter, and loss to each carrier gateway and your uplink. Configure RTCP statistics in sip-vicidial.conf and parse the logs into a database table for trending and correlation. When call quality issues arise, overlay Smokeping graphs (network-level view) with RTCP metrics (call-level view) to determine if the problem is the network path, the carrier, your ISP, or Asterisk configuration.
Start by establishing baseline metrics for each carrier during normal hours. Document acceptable jitter (<30ms), loss (<0.5%), and latency ranges (<100ms). When problems occur, query the quality table by hour and carrier to identify when the issue started and which carriers or paths are affected.
Key diagnostics to implement:
- Smokeping config updated with all carriers and gateways.
- RTCP logging enabled in sip-vicidial.conf and voip_call_quality table created.
- Automated hourly RTCP parsing script running via cron.
- Hourly or daily quality report script comparing Smokeping and RTCP metrics.
Check next:
- Is your Asterisk server's external IP and NAT settings correct in sip-vicidial.conf.
- Are firewall rules allowing RTP return traffic on high ports (10000-20000).
- Has your QoS configuration prioritized SIP and RTP over bulk data.
- Do you have a second carrier or ISP link to failover to when one degrades.