437 lines
14 KiB
Markdown
437 lines
14 KiB
Markdown
# Videochat-Umsetzungsplan
|
|
|
|
## Ziel
|
|
|
|
YpChat soll Videochat innerhalb einer bestehenden 1:1-Konversation unterstützen.
|
|
|
|
Rahmenbedingungen:
|
|
|
|
- Videochat ist nur aus einer bestehenden Chat-Konversation heraus erreichbar.
|
|
- Die Videochat-Funktion soll nur sichtbar sein, wenn beide Gesprächspartner sie für diese Konversation erlaubt haben.
|
|
- Es darf keine Direktverbindung zwischen den Endgeräten geben.
|
|
- Sämtliche Videoverbindungen laufen über Server-Infrastruktur, damit keine Peer-IP-Adressen offengelegt werden.
|
|
|
|
## Empfohlene Architektur
|
|
|
|
### 1. Trennung zwischen Chat-Signaling und Medien-Relay
|
|
|
|
Die bestehende Socket.IO-Infrastruktur bleibt für:
|
|
|
|
- Sichtbarkeit der Video-Funktion
|
|
- Freigabe-Status pro Konversation
|
|
- Einladung / Annahme / Ablehnung
|
|
- Klingelstatus
|
|
- Gesprächsstatus
|
|
- Fehler- und Abbruchsignale
|
|
|
|
Der Austausch der Grunddaten und Anfragen darf über Socket.IO laufen.
|
|
|
|
Die eigentlichen Audio-/Videoströme sollen ausdrücklich nicht über die bestehenden Chat-Sockets und nicht über die Chat-Message-Logik laufen, sondern über eine dedizierte serverseitige Medienebene.
|
|
|
|
### 2. Keine Peer-to-Peer-Verbindung
|
|
|
|
Empfehlung:
|
|
|
|
- WebRTC weiterverwenden, aber ausschließlich mit server-relaytem Medientransport
|
|
- kein P2P-Mesh
|
|
- keine Host-/srflx-Kandidaten verwenden
|
|
- nur relay-Kandidaten zulassen oder direkt eine SFU/Media-Server-Lösung einsetzen
|
|
|
|
Praktisch heißt das:
|
|
|
|
- Signaling kommt aus `server/broadcast.js`
|
|
- Medien laufen über einen separaten Media-Server oder eine integrierte SFU
|
|
- der Browser bzw. die mobilen Clients sehen nur die Server-Endpunkte, nicht die Gegenstelle
|
|
- Socket.IO transportiert nur Status, Einladungen, Freigaben und Session-Metadaten
|
|
- Audio/Video läuft ausschließlich über den Medienpfad
|
|
|
|
### 3. Bevorzugte Zielarchitektur
|
|
|
|
Für YpChat ist eine SFU-basierte 1:1-Lösung sinnvoller als vollständiges Server-Transcoding:
|
|
|
|
- bessere Latenz als kompletter zentraler Decode/Encode-Relay
|
|
- trotzdem keine direkte Verbindung zwischen Nutzern
|
|
- sauber erweiterbar für Android, iOS und Web
|
|
|
|
Planungsentscheidung:
|
|
|
|
- Node-Backend bleibt Orchestrator und Berechtigungsinstanz
|
|
- Video-Medienserver wird als eigene Komponente vorgesehen
|
|
- pro Videochat wird ein kurzlebiger Raum erzeugt
|
|
- Zutritt nur für die beiden durch den Chat verknüpften Nutzer
|
|
|
|
## Produktlogik
|
|
|
|
### 1. Sichtbarkeit
|
|
|
|
Die Videochat-Aktion ist nur sichtbar, wenn:
|
|
|
|
- `currentConversation` gesetzt ist
|
|
- beide Nutzer online bzw. erreichbar sind
|
|
- keine Blockierung aktiv ist
|
|
- beide Nutzer für genau diese Konversation `videoAllowed = true` gesetzt haben
|
|
|
|
Empfehlung:
|
|
|
|
- Freigabe nicht global pro Account, sondern pro Konversation speichern
|
|
- Freigabe explizit und widerrufbar machen
|
|
- Sichtbarkeit im Chat-Header und optional zusätzlich im Composer
|
|
|
|
### 2. Verbindungsgrenze pro Nutzer
|
|
|
|
Pro Nutzer dürfen maximal drei gleichzeitige Videoverbindungen aktiv sein.
|
|
|
|
Wenn ein vierter Videochat gestartet oder angenommen werden soll:
|
|
|
|
- lehnt der Server den Vorgang ab
|
|
- der anfragende Client erhält einen klaren Fehlerstatus
|
|
- die UI zeigt eine verständliche Meldung wie "Maximal drei Videoverbindungen gleichzeitig erlaubt"
|
|
|
|
Die Begrenzung muss serverseitig erzwungen werden, nicht nur in der UI.
|
|
|
|
### 3. Zustandsmodell pro Konversation
|
|
|
|
Pro Benutzerpaar wird zusätzlicher Konversationszustand benötigt:
|
|
|
|
- `localVideoConsent`
|
|
- `remoteVideoConsent`
|
|
- `videoVisible`
|
|
- `activeCallState`
|
|
- `incomingCall`
|
|
- `outgoingCall`
|
|
- `callRoomId`
|
|
|
|
Empfohlene Server-Zustände:
|
|
|
|
- `disabled`
|
|
- `local_allowed`
|
|
- `mutual_allowed`
|
|
- `ringing`
|
|
- `connecting`
|
|
- `active`
|
|
- `ended`
|
|
|
|
Zusätzlich pro Nutzer:
|
|
|
|
- `activeVideoConnectionCount`
|
|
- Liste aktiver Video-Sessions
|
|
- welches Video aktuell im Vordergrund ist
|
|
|
|
### 4. Gesprächsablauf
|
|
|
|
1. Nutzer A öffnet eine bestehende Konversation.
|
|
2. Nutzer A aktiviert "Videochat erlauben".
|
|
3. Nutzer B aktiviert dieselbe Freigabe.
|
|
4. Erst jetzt wird der Videochat-Button sichtbar.
|
|
5. Nutzer A startet einen Anruf.
|
|
6. Server sendet Einladung an Nutzer B.
|
|
7. Nutzer B nimmt an oder lehnt ab.
|
|
8. Bei Annahme erzeugt der Server einen kurzlebigen Call-Raum und gibt signierte Join-Daten an beide Clients zurück.
|
|
9. Beide Clients verbinden sich mit dem Medienserver.
|
|
10. Auflegen, Timeout oder Disconnect beendet Raum und Status.
|
|
|
|
Wenn ein Nutzer bereits drei aktive Videoverbindungen hat, scheitert Schritt 5 oder 7 mit einem Serverfehler.
|
|
|
|
## Anzeige- und Layoutkonzept
|
|
|
|
### 1. Rechte Preview-Spalte
|
|
|
|
Alle aktiven Videoverbindungen eines Nutzers werden rechts als Preview angezeigt.
|
|
|
|
Vorgaben:
|
|
|
|
- Position rechts im Browserfenster
|
|
- Breite etwa `1/5` des Browserfensters
|
|
- ganz oben ein festes Self-Preview des eigenen Video-Streams
|
|
- darunter maximal drei Video-Previews fremder aktiver Verbindungen
|
|
- damit insgesamt bis zu vier Previews sichtbar
|
|
- jede Preview zeigt mindestens:
|
|
- Videobild
|
|
- Name des Partners
|
|
- Mute-Zustand
|
|
- Status
|
|
- Aktion zum In-den-Vordergrund-Holen, außer beim Self-Preview
|
|
- Aktion zum Beenden
|
|
|
|
Empfehlung:
|
|
|
|
- eigener Container im Web-Layout, nicht im normalen Chat-Message-Flow
|
|
- auf kleineren Viewports responsiv umschalten, aber Desktop bleibt Referenz
|
|
- das Self-Preview ist rein informativ und kann nicht in den Vordergrund geholt werden
|
|
|
|
### 2. Vordergrund-Video als schwebendes Fenster
|
|
|
|
Ein aktives Video kann in den Vordergrund geholt werden.
|
|
|
|
Vorgaben:
|
|
|
|
- Darstellung als schwebendes Fenster
|
|
- frei verschiebbar
|
|
- über der normalen Chat-Oberfläche
|
|
- pro Zeitpunkt genau ein Vordergrundfenster
|
|
- Rückweg in die rechte Preview-Leiste möglich
|
|
|
|
Das Vordergrundfenster sollte enthalten:
|
|
|
|
- großes Videobild der ausgewählten Verbindung
|
|
- Name des Partners sichtbar im Fenster
|
|
- Mute-Zustand sichtbar im Fenster
|
|
- optional eigenes kleines Self-Preview
|
|
- Drag-Handle
|
|
- Schließen / minimieren
|
|
- Mute / Kamera aus
|
|
- Auflegen
|
|
|
|
### 3. Zustände in der UI
|
|
|
|
Die UI braucht zusätzlich zu den Call-States:
|
|
|
|
- `videoDockSessions`
|
|
- `selfPreviewStream`
|
|
- `foregroundVideoSessionId`
|
|
- `floatingVideoPosition`
|
|
- `maxVideoConnectionsReached`
|
|
|
|
## Technischer Zuschnitt
|
|
|
|
## Phasenstatus
|
|
|
|
- [x] Phase 1: Signaling und Zustände im Backend
|
|
- [x] Phase 2: Web-Client
|
|
- [x] Phase 3: Android
|
|
- [ ] Phase 4: Medienserver-Integration und End-to-End-Test
|
|
- [x] Server- und Web-Relaypfad via WebRTC mit Relay-Only-Signaling
|
|
- [x] Native Android-Medienebene
|
|
|
|
### Phase 1: Signaling und Zustände im Backend
|
|
|
|
Erweiterung von `server/broadcast.js` um neue Event-Familien:
|
|
|
|
- `videoConsent:set`
|
|
- `videoConsent:update`
|
|
- `videoCall:invite`
|
|
- `videoCall:incoming`
|
|
- `videoCall:accept`
|
|
- `videoCall:reject`
|
|
- `videoCall:cancel`
|
|
- `videoCall:start`
|
|
- `videoCall:end`
|
|
- `videoCall:error`
|
|
- `videoCall:capacity`
|
|
|
|
Zusätzliche In-Memory-Strukturen:
|
|
|
|
- Konversations-Metadaten getrennt von `conversations`
|
|
- aktive Call-Sessions
|
|
- Mapping `conversationKey -> consent/call state`
|
|
- Mapping `userName -> aktive Video-Sessions`
|
|
|
|
Wichtig:
|
|
|
|
- Call-Zustand an stabile Benutzeridentitäten koppeln, nicht nur an Socket-IDs
|
|
- Blocklisten auch für Video-Einladungen durchsetzen
|
|
- bei Reconnect Call-Zustand defensiv neu synchronisieren
|
|
- Verbindungsobergrenze von drei aktiven Video-Sessions pro Nutzer serverseitig prüfen
|
|
|
|
Status:
|
|
|
|
- erledigt
|
|
|
|
### Phase 2: Web-Client
|
|
|
|
Im Web-Store `client/src/stores/chat.js` ergänzen:
|
|
|
|
- Video-Consent-Status pro aktueller Konversation
|
|
- neue Socket-Listener für Video-Events
|
|
- Actions zum Setzen der Freigabe
|
|
- Actions zum Starten, Annehmen, Ablehnen und Beenden eines Calls
|
|
- UI-Flags für Ringing, Connecting, Active, Failed
|
|
- Verwaltung von bis zu drei parallelen aktiven Video-Sessions
|
|
- Auswahl, welches Video im Vordergrund schwebt
|
|
- Position des schwebenden Fensters
|
|
- Fehlerzustand für Kapazitätsgrenze
|
|
|
|
UI-Einstiegspunkte:
|
|
|
|
- `client/src/views/ChatView.vue`
|
|
- Sichtbarer Videochat-Button im Header nur bei `mutual_allowed`
|
|
- rechte Preview-Spalte für aktive Videos
|
|
- `client/src/components/ChatInput.vue`
|
|
- optionaler Toggle "Video erlauben" oder sekundärer Einstieg
|
|
- `client/src/components/ChatWindow.vue`
|
|
- Statusbanner für Einladung, Verbindungsaufbau, aktiv, beendet
|
|
|
|
Zusätzliche neue Web-Komponente:
|
|
|
|
- `client/src/components/VideoCallPanel.vue`
|
|
- lokales Vorschaufenster
|
|
- entferntes Video
|
|
- Annehmen / Ablehnen
|
|
- Kamera/Mikro muten
|
|
- Auflegen
|
|
- `client/src/components/VideoDock.vue`
|
|
- rechte Preview-Spalte mit festem Self-Preview plus bis zu drei Partner-Previews
|
|
- `client/src/components/FloatingVideoWindow.vue`
|
|
- verschiebbares Vordergrundfenster
|
|
|
|
Status:
|
|
|
|
- erledigt
|
|
|
|
### Phase 3: Android
|
|
|
|
Erweiterungen:
|
|
|
|
- `android/app/src/main/java/de/ypchat/android/data/model/SocketEvent.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/model/Models.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/api/SocketClient.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/repository/ChatRepository.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/ui/YpChatRoot.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/ui/ChatViewModel.kt`
|
|
|
|
Benötigt werden:
|
|
|
|
- neue Eventklassen für Consent und Call-Status
|
|
- Repository-State für Sichtbarkeit, Einladung und aktiven Call
|
|
- UI für Toggle, Rufannahme und laufenden Call
|
|
- UI für bis zu drei Previews und ein hervorgehobenes Vordergrundvideo
|
|
- Medienintegration über dieselbe server-relayte Architektur wie im Web
|
|
|
|
Status:
|
|
|
|
- erledigt
|
|
|
|
### Phase 4: Medienserver-Integration und End-to-End-Test
|
|
|
|
Umfang:
|
|
|
|
- Auswahl und Einbindung der Relay-/SFU-Lösung
|
|
- Ausgabe serverseitiger Join-Daten für Calls
|
|
- Medienpfad an Web und Android anbinden
|
|
- End-to-End-Test aller Zustände
|
|
- Datenschutz- und Kapazitätsprüfungen abschließen
|
|
|
|
Aktueller Stand:
|
|
|
|
- Server und Web nutzen jetzt Relay-Only-WebRTC mit Signaling über Socket.IO
|
|
- tatsächliche Medien laufen nicht über Chat-Sockets
|
|
- Voraussetzung ist eine konfigurierte TURN-/Relay-Infrastruktur über Umgebungsvariablen
|
|
- Android nutzt jetzt ebenfalls den Relay-Only-WebRTC-Medienpfad mit nativer Laufzeit und Compose-Rendering
|
|
- offen bleibt vor allem der End-to-End-Test mit echter TURN-Konfiguration und Mehrgeräte-Verifikation
|
|
|
|
Status:
|
|
|
|
- offen
|
|
|
|
Benötigte Umgebungsvariablen für den Relay-Betrieb:
|
|
|
|
- `VIDEO_TURN_URLS`
|
|
- `VIDEO_TURN_USERNAME`
|
|
- `VIDEO_TURN_CREDENTIAL`
|
|
- optional `VIDEO_STUN_URLS`
|
|
- alternativ `VIDEO_ICE_SERVERS_JSON` als vollständige ICE-Serverliste
|
|
|
|
## Server-seitige Persistenzentscheidung
|
|
|
|
Für einen ersten Schritt kann der Consent-Zustand im RAM gehalten werden, analog zur aktuellen Chat-Architektur.
|
|
|
|
Empfehlung für produktiven Ausbau:
|
|
|
|
- Consent pro Benutzerpaar persistent speichern
|
|
- aktive Calls nur flüchtig speichern
|
|
|
|
Begründung:
|
|
|
|
- Sichtbarkeit des Video-Buttons soll nach Reconnect nicht zufällig verloren gehen
|
|
- aktive Calls dürfen bei Server-Neustart beendet werden, aber Consent sollte stabiler sein
|
|
|
|
## Sicherheits- und Datenschutzregeln
|
|
|
|
- Videochat nur für eingeloggte, aktive Chat-Teilnehmer
|
|
- keine Join-Daten ohne bestehende Konversation
|
|
- keine Join-Daten ohne gegenseitige Freigabe
|
|
- Blockierungen sperren auch Videochat
|
|
- Call-Räume sind kurzlebig und nur für zwei Teilnehmer gültig
|
|
- Tokens für Media-Join serverseitig signieren und kurz halten
|
|
- keine Offenlegung von Peer-IP-Adressen an Clients
|
|
- Logging nur auf Betriebsniveau, keine Speicherung von Medieninhalten
|
|
|
|
## Offene Architekturentscheidung
|
|
|
|
Vor der Implementierung sollte genau eine Medienstrategie festgelegt werden:
|
|
|
|
### Empfohlene Richtung
|
|
|
|
Server-relayter WebRTC-Videochat mit SFU.
|
|
|
|
Warum:
|
|
|
|
- erfüllt die Anforderung "keine Direktverbindung"
|
|
- ist für Web, Android und iOS gemeinsam nutzbar
|
|
- passt besser zu Echtzeit als Datei- oder Socket-Binary-Transfer
|
|
|
|
### Nicht empfohlen
|
|
|
|
- Video als Upload-/Download-Mechanik wie bei Bildern
|
|
- vollständiger Eigenbau eines Medienprotokolls über Socket.IO
|
|
- klassisches P2P-WebRTC mit STUN-only
|
|
|
|
## Kritische Dateien für die spätere Umsetzung
|
|
|
|
- `server/broadcast.js`
|
|
- `server/index.js`
|
|
- `client/src/stores/chat.js`
|
|
- `client/src/views/ChatView.vue`
|
|
- `client/src/components/ChatInput.vue`
|
|
- `client/src/components/ChatWindow.vue`
|
|
- `android/app/src/main/java/de/ypchat/android/data/model/SocketEvent.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/model/Models.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/api/SocketClient.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/data/repository/ChatRepository.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/ui/YpChatRoot.kt`
|
|
- `android/app/src/main/java/de/ypchat/android/ui/ChatViewModel.kt`
|
|
|
|
## Verifikation
|
|
|
|
### Funktional
|
|
|
|
1. Zwei Nutzer bauen eine normale Konversation auf.
|
|
2. Nur ein Nutzer erlaubt Videochat.
|
|
3. Prüfen, dass keine Videochat-Aktion sichtbar ist.
|
|
4. Zweiter Nutzer erlaubt Videochat.
|
|
5. Prüfen, dass die Aktion jetzt bei beiden sichtbar ist.
|
|
6. Nutzer A startet einen Call.
|
|
7. Nutzer B erhält Einladung.
|
|
8. Nutzer B lehnt ab, Status muss sauber zurückspringen.
|
|
9. Nutzer A startet erneut, Nutzer B nimmt an.
|
|
10. Beide verbinden sich ausschließlich über den Server-Relay-Pfad.
|
|
11. Drei parallele Videoverbindungen für einen Nutzer aufbauen.
|
|
12. Vierte Verbindung starten oder annehmen und korrekte Fehlermeldung prüfen.
|
|
13. Prüfen, dass rechts ein Self-Preview plus maximal drei Partner-Previews sichtbar sind.
|
|
14. Prüfen, dass das Self-Preview nicht vergrößert werden kann.
|
|
15. Prüfen, dass unter jedem Partner-Preview der Name und der Mute-Zustand sichtbar sind.
|
|
16. Ein Partner-Preview in den Vordergrund holen und als schwebendes Fenster verschieben.
|
|
17. Prüfen, dass auch im großen Fenster Name und Mute-Zustand sichtbar sind.
|
|
18. Minimieren und Rückkehr in die Preview-Leiste prüfen.
|
|
19. Auflegen, Browser-Reload, App-Hintergrundwechsel und Reconnect prüfen.
|
|
|
|
### Datenschutz
|
|
|
|
1. Prüfen, dass keine direkte Peer-Verbindung aufgebaut wird.
|
|
2. Prüfen, dass nur Relay-/Server-Kandidaten verwendet werden.
|
|
3. Prüfen, dass Blockierungen auch Video-Einladungen unterbinden.
|
|
|
|
### Regression
|
|
|
|
1. Textnachrichten weiter senden/empfangen.
|
|
2. Bildversand weiter senden/empfangen.
|
|
3. History, Inbox und Conversation-Reload dürfen unverändert funktionieren.
|
|
|
|
## Empfohlene Implementierungsreihenfolge
|
|
|
|
1. Event- und Zustandsmodell für Consent und Call-Lifecycle definieren.
|
|
2. Backend-Signaling in `server/broadcast.js` ergänzen.
|
|
3. Web-Client vollständig integrieren und als Referenzfluss stabilisieren.
|
|
4. Danach Android und iOS auf denselben Event-Vertrag heben.
|
|
5. Erst dann Medienserver produktionsnah anbinden und End-to-End testen.
|