Make it yours

Video calls

Set up the TURN relay that carries video calls and group video calls.

How video calls work

Players start a video call from a contact's video button or from a video call in Recents. Voice stays on pma-voice; the picture from each phone's selfie camera goes through a TURN relay, so players never see each other's IP address.

Group video calls hold up to four people. Players start one with the video button at the top of a group conversation in Messages, and can join a group's call while it is on. Voice-only group calls hold up to eight. Clips Live streams go through the same relay.

Until a relay is set up, the video call button on a contact is greyed out, the group video button in Messages is hidden, and video calls are refused. Voice calls are not affected.

Choose one relay in config/calls_server.lua, which is loaded on the server only:

lua
Config.CallRelay = {
    relay = 'coturn',   -- 'coturn' | 'cloudflare' | 'metered' | 'static'
    ...
}
RelayCostWhat you need
coturnFreeYour own coturn server with a public IP
cloudflarePaid per GBA Cloudflare Realtime TURN key
meteredPaid per GBA Metered.ca TURN app
staticDepends on the providerAny TURN server with a fixed username and password

Each call gets its own temporary relay login made on your server; your secret, token or API key never reaches players. To keep your relay choice through updates, set it in a file in config/local/server/, such as Config.CallRelay.relay = 'cloudflare'.

Expect about 1 Mbps through the relay per active video call at good signal. In a group video call every pair of people has its own link: three people make 3 links, four people 6 links, about 6 Mbps.

Option A: coturn

coturn is the standard open-source TURN server. It needs a public IP and a few open ports. It can run on the same machine as FiveM or on a small separate VPS. You can use any ports; these examples use 41820 instead of the common 3478.

Linux (Ubuntu or Debian)

bash
sudo apt install coturn
sudo sed -i 's/#TURNSERVER_ENABLED=1/TURNSERVER_ENABLED=1/' /etc/default/coturn
openssl rand -hex 32

The last command prints your shared secret: copy it. Then replace the settings file, keeping the original:

bash
sudo mv /etc/turnserver.conf /etc/turnserver.conf.orig
sudo nano /etc/turnserver.conf

Paste this, replacing the secret and hostname:

/etc/turnserver.conf
listening-port=41820
# Optional TURNS, see "Strict networks" below
# tls-listening-port=41821
fingerprint
use-auth-secret
static-auth-secret=PASTE_THE_SECRET_HERE
realm=turn.yourserver.com
# Video goes over this UDP range (~2 ports per active call; per link in a group video call)
min-port=49160
max-port=49200
no-cli
no-multicast-peers
# Never relay into private networks (protects your server's LAN)
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
# Only if the machine is behind NAT:
# external-ip=PUBLIC_IP/PRIVATE_IP

Start coturn and open its ports:

bash
sudo systemctl enable --now coturn
sudo systemctl restart coturn
sudo systemctl status coturn --no-pager
sudo ufw allow 41820/udp
sudo ufw allow 41820/tcp
sudo ufw allow 49160:49200/udp

The status should say active (running). If it does not, sudo journalctl -u coturn -n 30 shows why.

The range 49160 to 49200 gives about 20 calls at once. Widen min-port and max-port (and the firewall rule) if you expect more, counting a four-person group video call as six.

Windows (Docker)

coturn is made for Linux, so on Windows run it with Docker Desktop. Save the turnserver.conf above next to this file, with external-ip=YOUR_PUBLIC_IP set in it:

docker-compose.yml
services:
  coturn:
    image: coturn/coturn
    restart: unless-stopped
    ports:
      - "41820:41820/udp"
      - "41820:41820/tcp"
      - "49160-49200:49160-49200/udp"
    volumes:
      - ./turnserver.conf:/etc/coturn/turnserver.conf:ro
PowerShell
docker compose up -d
New-NetFirewallRule -DisplayName "coturn" -Direction Inbound -Protocol UDP -LocalPort 41820,49160-49200 -Action Allow
New-NetFirewallRule -DisplayName "coturn tcp" -Direction Inbound -Protocol TCP -LocalPort 41820 -Action Allow

If the server sits behind a router, forward the same ports to it.

Connect the phone to coturn

In config/calls_server.lua:

lua
relay = 'coturn',
coturn = {
    host = 'turn.yourserver.com',  -- or the public IP
    port = 41820,                  -- same as listening-port
    tlsPort = nil,                 -- same as tls-listening-port, if you set one
    secret = '',                   -- leave empty and use server.cfg
    ttlSeconds = 3600,
},

And in server.cfg, the same secret as static-auth-secret:

server.cfg
set NOVA_TURN_SECRET "PASTE_THE_SECRET_HERE"

You can keep every coturn value out of the config file instead: leave host and secret empty and set NOVA_TURN_HOST, NOVA_TURN_PORT and NOVA_TURN_SECRET in server.cfg. Use set, not setr: setr sends the value to players.

Strict networks. Some school, office and ISP networks block unusual UDP ports. For those players, also enable TURNS over TCP: add tls-listening-port, cert= and pkey= (for example your Let's Encrypt certificate for the hostname) to turnserver.conf, open that TCP port, and set tlsPort in the phone config. Port 443 gets through almost everywhere, if nothing else on the machine uses it.

Option B: Cloudflare

  1. In the Cloudflare dashboard, open Realtime → TURN Server and create a TURN key. Copy its Turn Token ID and API Token.
  2. In config/calls_server.lua, set relay = 'cloudflare' and cloudflare.keyId = 'your-token-id'.
  3. In server.cfg: set NOVA_TURN_CLOUDFLARE_TOKEN "your-api-token".

Option C: Metered

  1. At metered.ca, create a TURN app and copy your app name (the part before .metered.live) and a TURN API key.
  2. In config/calls_server.lua, set relay = 'metered' and metered.appName = 'yourapp'.
  3. In server.cfg: set NOVA_TURN_METERED_KEY "your-api-key".

Option D: another provider

If your provider gives a fixed URL, username and password, set relay = 'static' and fill static.urls (for example { 'turn:turn.example.com:3478?transport=udp' }), username and credential. Fixed credentials cannot expire per call, so prefer the options above.

Test the relay

  1. Restart the resource and run phoneadmin relay in the server console. It shows whether the relay is configured and prints a temporary test login. phoneadmin selftest report also checks it ([PASS] video call relay coturn).
  2. Open the WebRTC Trickle ICE page, add the printed URL, username and password, and click Gather candidates. A row with type relay means the relay works.
  3. Make a video call in game: open a contact and tap the video button.

Picture quality and battery

The picture follows the call's signal bars, using the worse of the two phones. It stays clear at three bars or more and gets choppier, smaller and glitchier at two bars or fewer. Tune this per bar count in Config.VideoCalls.quality in config/communication.lua.

In a group video call, each phone splits its bitrate between the people it sends to, never below Config.GroupCalls.minVideoBitsPerSecond (120 kbps). The other group call limits are in the same Config.GroupCalls; see Group calls. Config.VideoCalls.enabled = false turns video calls off entirely.

Video calls start on speaker, use mobile data (about 5 MB per minute on each side, free on Wi-Fi) and drain the battery faster than voice calls. In a group, each person pays for their own data, and running out of data or signal only takes that person out. Low Power Mode turns video calls off. Putting the phone away pauses the player's camera.

Troubleshooting

ProblemFix
Video buttons are greyed out or missingThe relay is not configured. phoneadmin relay says what is missing
"Video couldn't connect"The relay cannot be reached. Check the ports are open in the firewall and router, external-ip if behind NAT, and that host and port match turnserver.conf
phoneadmin relay prints relay API HTTP 401The Cloudflare token or Metered key is wrong
Works for most players but not oneTheir network blocks your UDP port. Set up TURNS over TCP (see Strict networks)

Available

Wolfden Phone

$89.99

or $19.99 a month, first 30 days free

Was this page helpful?
Made with care, by Wolfden.
© 2026 Wolfden StudiosBuilt for the stories you create.