# aether-admin — Media-Server (WebRTC-SFU) Router für die Live-Kameras des Admin-Panels. Er läuft **außerhalb** von FiveM als eigener Node-Prozess und macht zweierlei: - **Signaling + Medien (WebSocket, Standard `:8787`)** — Publisher senden ihren Stream, Viewer empfangen ihn. Der Server leitet die RTP-Pakete weiter (Selective Forwarding Unit). - **Token-Ausgabe (HTTP, Standard `:8788`)** — nur der FiveM-Server ruft das auf, abgesichert über ein gemeinsames Geheimnis. Der FiveM-Server routet **kein Video** — er prüft nur Rechte, stellt Token aus und weist Ziel-Clients an zu senden. ## Einrichtung ```bash cd resources/[aether]/aether-admin/media-server npm install AETHER_MEDIA_SECRET="ein-langes-zufaelliges-geheimnis" node server.js ``` ### Umgebungsvariablen | Variable | Standard | Bedeutung | |---|---|---| | `AETHER_MEDIA_SECRET` | *(leer)* | Gemeinsames Geheimnis. **Muss** gesetzt sein und exakt der FiveM-Convar `aether_admin_media_secret` entsprechen. | | `AETHER_MEDIA_WS_PORT` | `8787` | WebSocket-Port (von den NUIs erreichbar). | | `AETHER_MEDIA_HTTP_PORT` | `8788` | HTTP-Port für die Token-Ausgabe (nur vom FiveM-Server erreichbar). | ### Passende FiveM-Convars (in `server.cfg`) ```cfg set aether_admin_media_secret "ein-langes-zufaelliges-geheimnis" set aether_admin_media_http "http://127.0.0.1:8788" ``` Und in `resources/[aether]/aether-admin/shared/config.lua` die öffentliche WebSocket-Adresse (die die Spieler-Clients erreichen): ```lua AdminConfig.Media.url = 'ws://DEINE-OEFFENTLICHE-IP:8787' ``` > Für den Produktivbetrieb hinter TLS (`wss://`) einen Reverse-Proxy > (nginx/Caddy) vor den WS-Port setzen und die `url` auf `wss://…` zeigen. ## Die Videoquelle Der Publisher in `html/js/webrtc.js` holt sich den Stream in dieser Reihenfolge: 1. **`getDisplayMedia` — der Standardweg ohne externes Werkzeug.** Die NUI gibt das Spielfenster über die Bildschirmfreigabe-API frei; das ist echtes, flüssiges Video und braucht **kein OBS und keine Virtual-Cam**. 2. `window.__aetherCapture()` — optionaler Override, falls du eine bestimmte Quelle erzwingen willst (z. B. ein Aufnahmegerät). 3. Ein rot beschrifteter **Platzhalter** — erscheint nur, wenn die Bildschirmfreigabe abgelehnt/blockiert wurde, damit die Strecke trotzdem nachweislich live ist. **Die entscheidende Abhängigkeit:** Ob `getDisplayMedia` klappt, hängt davon ab, ob das **FiveM-CEF des Ziel-Clients** Bildschirmaufnahme aus einer Hintergrund-NUI erlaubt (Nutzergesten-/Berechtigungskontext). Erlaubt es das, siehst du das Live-Bild flüssig im Panel. Verweigert es das, kann kein Resource das erzwingen — dann bleibt nur eine externe Quelle über `__aetherCapture` oder die native Spectate-Funktion (Knopf „Beobachten"). Das Panel meldet pro Ziel-Client zurück, was gegriffen hat: eine Toast-Meldung „Bild live" oder „Bildschirmfreigabe blockiert (Fehlergrund)". ## Betrieb & Hinweise - Als Dienst betreiben (pm2/systemd), Neustart bei Absturz. - **Live-Test nötig:** Ein WebRTC-SFU lässt sich nur im laufenden Betrieb sinnvoll prüfen. Je nach `werift`-Version können Details der Signaling- oder RTP-API minimal abweichen — der Code ist die klar strukturierte Referenz und an einer Stelle (`publisherTrack`) leicht anzupassen. - Ohne gesetztes Geheimnis lehnt der Server jede Token-Ausgabe ab; das Panel zeigt dann den Hinweis „Media-Server nicht erreichbar".