aether-framework/resources/[aether]/aether-admin/media-server/README.md
Jerrit Fritzsche e4b82dd685 Aether-Framework: Fachmodule, Admin-Panel und Docker-Datenbank
- aether-medical: Stationen/Belegung, Intensivstation, Blutbank, Fuhrpark,
  Nachrichten/Aushänge, Berichte und Textbausteine (server + NUI)
- aether-admin: vollständiges Server-Admin-Panel als echtes FiveM-Resource,
  an aether-core gekoppelt (Rechte über aether_users.admin_group), mit
  WebRTC-Live-Kameras (Bildschirmfreigabe) und separatem Media-Server (SFU)
- Prototypen admin/ vervollständigt
- SQL-Schema aether_admin.sql
- Docker-Compose mit MariaDB und idempotenter Auto-Migration (schema_migrations)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 18:55:32 +02:00

80 lines
3.4 KiB
Markdown

# 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".