DEV Community

Jason Shouldice
Jason Shouldice

Posted on • Edited on • Originally published at vicistack.com

Getting WebRTC Working in VICIdial Without Losing a Weekend

Most call centers I manage now have 60-80% remote agents. The days of IP desk phones on every desk are fading. VICIdial handles this through ViciPhone — a built-in browser-based softphone that lets agents take calls directly in their web browser. No softphone install, no VPN, no port forwarding on the agent's home router.

When it works, it's elegant. When it doesn't, you're chasing one-way audio, certificate errors, and NAT traversal problems that make experienced sysadmins question their career choices.

Here's how to set it up and how to fix it when it breaks.

The Architecture

Three components:

  1. ViciPhone — JavaScript SIP client in the agent's browser. Uses JsSIP for SIP signaling over WebSocket and WebRTC for audio.
  2. Asterisk — Handles SIP registration, call routing, media processing. Must accept WebSocket connections (WSS) and DTLS-SRTP for encrypted media.
  3. The signaling path — Browser establishes a WebSocket to Asterisk on port 8089 (WSS). SIP messages travel over WebSocket. Audio negotiated via ICE, flows as encrypted SRTP.

The key constraint: WebRTC requires HTTPS. Modern browsers won't allow microphone access on non-secure origins. Self-signed certificates will cause problems. Get a real cert.

Step 1: SSL Certificate

Let's Encrypt is free and works:

sudo dnf install -y certbot
sudo certbot certonly --standalone -d vicidial.yourdomain.com
Enter fullscreen mode Exit fullscreen mode

Set up auto-renewal:

echo "0 3 * * * certbot renew --quiet --post-hook 'systemctl reload httpd && asterisk -rx \"module reload res_pjsip.so\"'" | sudo crontab -
Enter fullscreen mode Exit fullscreen mode

The post-hook reloads both Apache and PJSIP after renewal so Asterisk picks up the new cert without a restart.

Step 2: Use PJSIP, Not chan_sip

PJSIP has native WebSocket transport, full DTLS-SRTP support, full ICE negotiation, and multiple transports per endpoint. chan_sip is deprecated and removed in Asterisk 21. If you're setting up fresh, use PJSIP.

Required Asterisk modules: res_pjsip.so, res_pjsip_transport_websocket.so, res_http_websocket.so, res_pjsip_dtls.so, codec_opus.so.

Verify they're loaded:

asterisk -rx "module show like pjsip"
asterisk -rx "module show like websocket"
Enter fullscreen mode Exit fullscreen mode

Step 3: Asterisk HTTP and PJSIP Configuration

Enable the HTTP server for WebSocket in /etc/asterisk/http.conf:

[general]
enabled=yes
bindaddr=0.0.0.0
bindport=8088
tlsenable=yes
tlsbindaddr=0.0.0.0:8089
tlscertfile=/etc/letsencrypt/live/vicidial.yourdomain.com/fullchain.pem
tlsprivatekey=/etc/letsencrypt/live/vicidial.yourdomain.com/privkey.pem
Enter fullscreen mode Exit fullscreen mode

Port 8089 must be accessible from agents' networks.

In pjsip.conf, define the WebSocket transport:

[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
cert_file=/etc/letsencrypt/live/vicidial.yourdomain.com/fullchain.pem
priv_key_file=/etc/letsencrypt/live/vicidial.yourdomain.com/privkey.pem
external_media_address=YOUR_PUBLIC_IP
external_signaling_address=YOUR_PUBLIC_IP
Enter fullscreen mode Exit fullscreen mode

The external_media_address and external_signaling_address tell Asterisk to advertise its public IP in SIP/SDP messages — essential when Asterisk is behind a NAT.

Create a WebRTC endpoint template:

[webrtc-endpoint](!)
type=endpoint
transport=transport-wss
context=default
disallow=all
allow=opus
allow=g722
allow=ulaw
webrtc=yes
dtls_auto_generate_cert=yes
Enter fullscreen mode Exit fullscreen mode

The webrtc=yes shorthand (Asterisk 16+) sets AVPF, DTLS, ICE, and RTCP mux in one line.

Step 4: VICIdial Admin Settings

In Admin > System Settings:

  • WebRTC Phone Enabled: Y
  • WebSocket URL: wss://vicidial.yourdomain.com:8089/ws

For each remote agent, create a Phone entry with the WebRTC-compatible protocol set to PJSIP. VICIdial generates the PJSIP configuration from the phone table.

When agents log in, ViciPhone loads automatically. The browser prompts for microphone permission on first use.

NAT Traversal: The #1 Problem

Most remote agents are behind residential NAT. Symptoms: one-way audio, no audio at all, or audio that works briefly then drops.

STUN servers help browsers discover their public IP. Google's public servers work:

stun:stun.l.google.com:19302
stun:stun1.l.google.com:19302
Enter fullscreen mode Exit fullscreen mode

TURN servers relay media when STUN fails (symmetric NAT, corporate firewalls, CGNAT). Self-hosted coturn is recommended for production. Metered.ca offers a managed option if you don't want to run your own.

Configure STUN/TURN in ViciPhone's settings and verify the external_media_address is set correctly in pjsip.conf.

Common Fixes

One-way audio: Almost always a NAT issue. Check that external_media_address is set to your public IP. Verify STUN is configured. Try adding a TURN server.

Certificate errors: The SSL cert must match the hostname agents use. Wildcard certs work. Self-signed certs don't.

Registration failures: Check firewall — port 8089 must be open. Verify PJSIP modules are loaded. Check that the phone entry matches the PJSIP endpoint.

Ogg/Opus codec issues: Prefer Opus for WebRTC (better quality at lower bandwidth). Fall back to G.722 or ulaw if Opus isn't compiled.

ViciStack handles the full WebRTC deployment for remote agents — SSL, PJSIP, NAT traversal, TURN servers, and ongoing troubleshooting. $150/agent/month.

Originally published at https://vicistack.com/blog/vicidial-webrtc-setup/

Top comments (0)