# WebRTC

VidMeet is the WebRTC-based video calling system built into GKSPHONE. This guide explains every setting in the `Cfg.VidMeet` block inside `gksphone/config/serverconfig.lua` and walks you through both setup modes.

***

## Configuration Block Reference

```lua
Cfg.VidMeet = {
    Enabled    = true,

    -- ICE Server type: "cloudflare" | "manual"
    IceServer  = "manual",

    Cloudflare = {
        TokenID  = "",
        ApiToken = "",
        TTL      = 86400
    },

    ManualIceServers = {
        { urls = "stun:stun.cloudflare.com:3478" },
        { urls = "stun:stun.l.google.com:19302" },
        -- ...
    }
}
```

| Key                   | Type    | Default     | Description                                            |
| --------------------- | ------- | ----------- | ------------------------------------------------------ |
| `Enabled`             | boolean | `true`      | Enables or disables the video call feature entirely    |
| `IceServer`           | string  | `"manual"`  | ICE server mode: `"cloudflare"` or `"manual"`          |
| `Cloudflare.TokenID`  | string  | `""`        | Cloudflare TURN Server Application ID (Turn Token ID)  |
| `Cloudflare.ApiToken` | string  | `""`        | Cloudflare API Token (with Calls Edit permission)      |
| `Cloudflare.TTL`      | number  | `86400`     | TURN credential lifetime in seconds (86400 = 24 hours) |
| `ManualIceServers`    | array   | (STUN list) | RTCIceServer\[] used when `IceServer = "manual"`       |

***

## ICE Server Modes

### Mode 1: `"manual"` (Default)

Uses the `ManualIceServers` array you define. The default list contains public STUN servers only, which work for most peer-to-peer connections but **may fail when both players are behind strict NATs or firewalls** (e.g., corporate networks, CGNAT).

When to use: Development, testing, or when your player base has standard home networks.

Limitations:

* STUN only — no TURN relay fallback
* Video calls may fail for \~15–20 % of NAT configurations
* No cost, no credentials needed

Adding a TURN server (recommended for production):

```lua
ManualIceServers = {
    { urls = "stun:stun.l.google.com:19302" },
    -- Your TURN server:
    { urls = "turn:turn.yourdomain.com:3478",  username = "user", credential = "secret" },
    { urls = "turns:turn.yourdomain.com:5349", username = "user", credential = "secret" },
}
```

> `turns:` uses TLS (port 5349) and is required for HTTPS pages.

***

### Mode 2: `"cloudflare"` (Recommended for Production)

Uses [Cloudflare Realtime TURN Server](https://developers.cloudflare.com/calls/turn/) to generate short-lived TURN credentials automatically. Cloudflare's global anycast TURN network provides low-latency relays worldwide.

**When to use**: Production servers, large player bases, or whenever you want maximum call reliability.

**Advantages over manual TURN**:

* Global Anycast network — players connect to the nearest relay
* Auto-rotating credentials (no static secrets in config)
* Pay-as-you-go pricing (first 1,000 participant-minutes/month are free)
* No self-hosted infrastructure to maintain

***

## Setting Up Cloudflare TURN Server (Step-by-Step)

{% stepper %}
{% step %}

### Step 1 — Create a Cloudflare Account

Go to [dash.cloudflare.com](https://dash.cloudflare.com/?to=/:account/calls) and sign up or log in.
{% endstep %}

{% step %}

### Step 2 — Navigate to TURN Server

1. In the left sidebar, expand **Media**.
2. Expand **Realtime** under it.
3. Click **TURN Server**.

> Navigation path: **Media → Realtime → TURN Server**
> {% endstep %}

{% step %}

### Step 3 — Create a TURN Server App

1. On the TURN Server page, click **Create a TURN Server app**.
2. Give it a name (e.g., `gksphone-vidmeet`).
3. After clicking create, you will see **two values on the same page**:
   * **Turn Token ID** — this is your `TokenID`
   * **API Token** (64-character hex string) — this is your `ApiToken`

{% hint style="warning" %}
**Critical:** The page will show a warning: "Make sure to copy your API Token now. You won't be able to see it again." — Copy the API Token immediately before closing the page.
{% endhint %}
{% endstep %}

{% step %}

### Step 4 — Configure serverconfig.lua

```lua
Cfg.VidMeet = {
    Enabled   = true,
    IceServer = "cloudflare",

    Cloudflare = {
        TokenID  = "your-app-id-here",       -- App ID from Step 3
        ApiToken = "your-api-token-here",    -- API Token from Step 4
        TTL      = 86400                     -- 24 hours (adjust as needed)
    },

    -- ManualIceServers is ignored when IceServer = "cloudflare"
    ManualIceServers = { ... }
}
```

{% endstep %}

{% step %}

### Step 5 — Verify

Restart your FiveM server and attempt a video call in-game. Check the server console for any Cloudflare API errors.
{% endstep %}
{% endstepper %}

***

### TTL (Credential Lifetime) <a href="#ttl-credential-lifetime" id="ttl-credential-lifetime"></a>

The `TTL` value controls how long each set of TURN credentials remains valid. The server generates fresh credentials for every new call.

| TTL Value | Duration | Recommendation                              |
| --------- | -------- | ------------------------------------------- |
| `3600`    | 1 hour   | **Default — ideal for \~30 min sessions**   |
| `86400`   | 24 hours | Unnecessarily long, increases exposure risk |
| `604800`  | 7 days   | Debug only, never use in production         |

Average VidMeet session is \~30 minutes. `3600` gives a comfortable 1-hour window while minimizing the risk of credential misuse if intercepted.

***

## STUN vs TURN — What's the Difference?

| Protocol | Purpose                       | Required when                                    |
| -------- | ----------------------------- | ------------------------------------------------ |
| **STUN** | Discovers your public IP/port | Always (free, low traffic)                       |
| **TURN** | Relays media through a server | One or both peers are behind strict NAT/firewall |

Most home routers work fine with STUN only. TURN becomes essential when:

* Players are on mobile data (CGNAT is common)
* Players are behind corporate/university firewalls
* Players are on VPNs that block peer-to-peer UDP

***

## Troubleshooting

| Symptom                                  | Likely Cause                           | Fix                                                              |
| ---------------------------------------- | -------------------------------------- | ---------------------------------------------------------------- |
| Video calls connect but drop immediately | NAT traversal failing                  | Add a TURN server or switch to Cloudflare mode                   |
| "Cloudflare API error 403" in console    | Wrong `ApiToken` or missing permission | Recreate token with Calls Edit permission                        |
| "Cloudflare API error 404" in console    | Wrong `TokenID`                        | Double-check Turn Token ID in **Media → Realtime → TURN Server** |
| Calls work locally but not on production | Server firewall blocking UDP           | Open UDP 3478 (STUN/TURN) or use `turns:` on TCP 5349            |
| High call latency for some players       | STUN only, no TURN relay               | Enable TURN — Cloudflare mode routes to nearest PoP              |

***


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.gkshop.org/gksphone-v2/configuration/webrtc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
