# Video Calls

This guide explains how to set up **TURN relay** for YSeries video calls.

YSeries supports two RTC relay providers:

* **Cloudflare TURN** (managed, API-generated ICE servers)
* **Coturn** (self-hosted TURN, TURN REST shared-secret credentials)

If you don't configure a relay provider, video calls may still work on open networks, but **NAT/firewall users will often get black screens / frozen video**.

## Choose a Provider (Quick)

* Pick **Cloudflare** if you want the easiest setup and don't want to host TURN yourself.
* Pick **Coturn** if you want full control, self-hosting, or you already run your own TURN server.

## What is TURN?

TURN (Traversal Using Relays around NAT) relays WebRTC media when direct peer-to-peer connectivity fails.

**Benefits of using a TURN relay:**

* ✅ Better reliability for restrictive networks (NAT/firewalls)
* ✅ Time-limited/dynamic credentials (more secure than static TURN users)

## Prerequisites

* Access to your FiveM server configuration files
* Ability to restart your server/resource after configuration changes

## Common Config (Applies to Both)

The provider selection lives in `config/config.upload.lua`:

```lua
Config.RTCRelay = {}
Config.RTCRelay.Enabled = true          -- Enable dynamic RTC relay
Config.RTCRelay.Provider = "cloudflare" -- Options: "cloudflare", "coturn"
Config.RTCRelay.StripStun = false       -- Keep STUN servers (recommended)
Config.RTCRelay.CredentialTTL = 86400   -- Credential TTL in seconds (max: 86400)
```

After setting a provider, continue with the matching section below.

***

## Provider: Cloudflare (Managed TURN)

Cloudflare TURN generates ICE servers via API and automatically handles credential creation/revocation.

**Cloudflare benefits:**

* ✅ Free tier: 1,000 GB of data per month
* ✅ Globally distributed servers for low latency

### Step 1: Create Cloudflare Account

1. Visit [cloudflare.com](https://www.cloudflare.com/) and sign up for a free account
2. Complete the account verification process

### Step 2: Generate TURN Credentials

1. Log in to your Cloudflare dashboard
2. Navigate to **Realtime** → **TURN Server**(Search in the search bar for "TURN Server")
3. Click **Create** to generate a new TURN key
4. Copy the following credentials:
   * **Turn Token ID** (a long string)
   * **API Token** (another long string)

⚠️ **Important:** Keep these credentials secure and never share them publicly.

### Step 3: Configure Server Credentials

Open `server/apiKeys.lua` and locate the `RTCRelaySecrets` section:

```lua
RTCRelaySecrets = {
    token = GetConvar("yseriesRTCRelayToken", nil), -- Turn Token ID from Cloudflare
    apiKey = GetConvar("yseriesRTCRelayApiKey", nil) -- API Token from Cloudflare
}
```

**Option A: Using Convars (Recommended)**

Add these lines to your `server.cfg`:

```cfg
set yseriesRTCRelayToken "YOUR_TURN_TOKEN_ID_HERE"
set yseriesRTCRelayApiKey "YOUR_API_TOKEN_HERE"
```

**Option B: Direct Configuration**

Replace `nil` with your credentials directly in `apiKeys.lua`:

```lua
RTCRelaySecrets = {
    token = "YOUR_TURN_TOKEN_ID_HERE",
    apiKey = "YOUR_API_TOKEN_HERE"
}
```

### Step 4: Enable Cloudflare Provider

In `config/config.upload.lua`:

```lua
Config.RTCRelay.Enabled = true
Config.RTCRelay.Provider = "cloudflare"
```

### Step 5: Restart Server/Resource

1. Save all configuration files
2. Restart your FiveM server

***

## Provider: Coturn (Self-Hosted TURN)

Coturn uses **TURN REST** shared-secret credentials, so each player gets **time-limited** TURN login details. The shared secret never goes to the client/UI.

### Step 1: Install + Configure Coturn

Set up coturn with:

* `lt-cred-mech`
* `use-auth-secret`
* `static-auth-secret=<sharedSecret>`

Your TURN server must be reachable from the internet and your firewall must allow the ports you use (commonly `3478` for TURN and `5349` for TURNS).

### Step 2: Configure Coturn URLs (No Secrets)

In `config/config.upload.lua`, set the URLs your clients should use:

```lua
Config.RTCRelay.Coturn = {
    Urls = {
        "turn:turn.example.com:3478?transport=udp",
        "turn:turn.example.com:3478?transport=tcp",
        "turns:turn.example.com:5349?transport=tcp",
    },
}
```

Notes:

* Use your domain or public IP.
* Use `turns:` only if you configured TLS on coturn.

### Step 3: Configure the Shared Secret (server.cfg)

Add this to your `server.cfg` (recommended, do not hardcode secrets in Lua):

```cfg
set yseriesRTCRelayCoturnSecret "REPLACE_WITH_SHARED_SECRET"
```

### Step 4: Enable Coturn Provider

In `config/config.upload.lua`:

```lua
Config.RTCRelay.Enabled = true
Config.RTCRelay.Provider = "coturn"
```

### Step 5: Restart Server/Resource

Save changes and restart your server (or at least restart the `yseries` resource).

## Configuration Options

| Option          | Type    | Default        | Description                                              |
| --------------- | ------- | -------------- | -------------------------------------------------------- |
| `Enabled`       | boolean | `false`        | Enable/disable dynamic RTC relay                         |
| `Provider`      | string  | `"cloudflare"` | TURN service provider: `"cloudflare"` or `"coturn"`      |
| `StripStun`     | boolean | `false`        | Remove STUN servers when using relay (not recommended)   |
| `CredentialTTL` | number  | `86400`        | Credential lifetime in seconds (max: 86400 = 24 hours)   |
| `Coturn.Urls`   | table   | `{}`           | List of TURN/TURNS URLs (only used when Provider=coturn) |

## How It Works

1. When a player initiates a video call, the system requests fresh TURN credentials from the configured provider
2. Credentials are generated with a configurable expiration time (default: 24 hours)
3. These credentials are used to establish the WebRTC connection
4. When the call ends or player disconnects:
   * Cloudflare credentials are revoked automatically
   * Coturn credentials simply expire (TURN REST)
5. If the provider is unavailable or misconfigured, the system falls back to static ICE servers (less reliable)

## Troubleshooting

### Video Calls Not Working

**Check 1: Verify Configuration**

* Ensure `Config.RTCRelay.Enabled = true` in `config/config.upload.lua`
* Ensure `Config.RTCRelay.Provider` matches what you set up (`cloudflare` or `coturn`)
* Cloudflare: verify credentials are set correctly in `server/apiKeys.lua` (or `server.cfg` convars)
* Coturn: verify `Config.RTCRelay.Coturn.Urls` is not empty and the `yseriesRTCRelayCoturnSecret` convar is set

**Check 2: Server Console**

* Look for error messages about missing credentials
* Cloudflare: check for API errors (status codes other than 201)
* Coturn: check for missing secret / empty URLs errors

**Check 3: Credentials**

* Cloudflare: verify your Turn Token ID and API Token are correct and not revoked
* Coturn: verify the `static-auth-secret` in your coturn config matches `yseriesRTCRelayCoturnSecret`

### Common Error Messages

**"RTC Relay is enabled but credentials are missing"**

* Solution: Add your credentials to `server/apiKeys.lua` or set convars in `server.cfg`

**"RTC Relay (coturn) is enabled but shared secret is missing"**

* Solution: add `set yseriesRTCRelayCoturnSecret "..."` to `server.cfg` and restart

**"RTC Relay (coturn) is enabled but Config.RTCRelay.Coturn.Urls is empty"**

* Solution: set `Config.RTCRelay.Coturn.Urls = { "turn:...", "turns:..." }` in `config/config.upload.lua`

**"Failed to get RTC relay credentials from Cloudflare. Status: 401"**

* Solution: Your API Token is incorrect or expired. Generate a new one in Cloudflare dashboard.

**"Failed to get RTC relay credentials from Cloudflare. Status: 404"**

* Solution: Your Turn Token ID is incorrect. Check it in Cloudflare dashboard.

### Fallback Behavior

If the configured TURN provider is unavailable or disabled, the system automatically uses the default ICE servers (this is unreliable and it can cause issues like black screen, frozen video calls, etc.). Video calls may still work, but will have reduced reliability in restrictive network environments.

## Monitoring Usage

### Cloudflare

1. Log in to Cloudflare dashboard
2. Navigate to **Realtime** → **TURN Server**
3. View usage statistics and monitor data consumption
4. Free tier includes 1,000 GB per month; additional usage costs $0.05 per GB

### Coturn

Monitor your server bandwidth and coturn logs. Because coturn is self-hosted, usage/cost depends entirely on your hosting provider.

## Security Best Practices

* ✅ Never commit credentials to version control
* ✅ Use convars in `server.cfg` instead of hardcoding in files
* ✅ Rotate credentials periodically
* ✅ Monitor usage for unusual activity
* ✅ Cloudflare: keep your account secure (2FA recommended)
* ✅ Coturn: keep your TURN host secured and patched

## Additional Resources

* [Cloudflare TURN Documentation](https://developers.cloudflare.com/realtime/turn/)
* [Cloudflare Pricing](https://developers.cloudflare.com/realtime/pricing/)
* [Coturn (GitHub)](https://github.com/coturn/coturn)

## Support

If you encounter issues not covered in this guide:

1. Check server console logs for detailed error messages
2. Enable `Config.DebugPrint = true` for additional debugging information
3. Verify your provider setup:
   * Cloudflare: account status, TURN key validity, API token permissions
   * Coturn: public reachability, firewall rules, and shared secret match
