Files
2026-08-22 20:34:42 +02:00

92 lines
4.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Screen Cast Bildschirm auf jeden Smart TV
Für Android-Geräte, denen der Hersteller kein Screen Mirroring spendiert hat.
Die App nimmt den Bildschirm auf, encodiert ihn hardwarebeschleunigt in H.264
und streamt ihn ins WLAN. Am Fernseher wird nur der Browser gebraucht.
## Zwei Wege zum Fernseher
### 1. Fernseher wartet schon auf eine Verbindung
Für Geräte im Screen-Mirroring-Modus etwa Hotelfernseher, an denen sich
nichts eintippen lässt. In der App auf **Zum Fernseher verbinden** tippen; die
Liste zeigt, was gefunden wurde:
* **Über den Übertragungsdienst von Android** vielen Handys fehlt nur die
Bedienkachel („Smart View“), nicht die Technik. Steht der Fernseher hier,
übernimmt Android die Übertragung selbst, in voller Qualität. Das ist der
beste Fall.
* **Direktverbindung über Wi-Fi Direct** die App baut die Verbindung selbst
auf und schickt das Bild im Miracast-Format hinüber. Läuft komplett am WLAN
vorbei, also auch in Gästenetzen, die Geräte voneinander abschotten.
Darunter liegt ein Protokoll, das jeden Schritt mitschreibt falls ein
bestimmter Fernseher zickt, steht dort, an welcher Stelle.
### 2. Fernseher mit Browser
1. App öffnen, **Übertragung starten**, Systemabfrage bestätigen
2. Am Fernseher den Browser öffnen
3. Die angezeigte Adresse eintippen, z. B. `http://192.168.1.42:8080`
4. Das Bild läuft im Vollbild. `F` (oder die farbige Taste der Fernbedienung,
die als F wirkt) schaltet zwischen *ganzes Bild* und *randlos füllend* um.
Handy und Fernseher müssen im selben WLAN sein. Die App darf in den
Hintergrund die Übertragung läuft als Vordergrunddienst weiter und lässt sich
über die Benachrichtigung beenden.
## Zweiter Ausgang für Player
`http://<adresse>:8080/stream.ts` liefert denselben Stream als MPEG-TS für
VLC, mpv oder Kodi („Netzwerkstream öffnen“), falls der Fernseher-Browser
streikt oder ein Laptop am Beamer hängt.
## Was beim Direktweg möglich ist und was nicht
Der Miracast-Handshake (M1M7 nach Wi-Fi-Display-Standard) und der RTP-Versand
sind vollständig umgesetzt und gegen einen nachgebauten Fernseher getestet.
Die Steuerverbindung baut **der Fernseher zu uns** auf, nicht umgekehrt so
sieht es der Standard vor, und so macht es Android intern auch
(`RemoteDisplay.listen`). Die App hört deshalb auf Port 7236 und 8554 zu,
sobald die Bildschirmfreigabe erteilt ist, und zwar *bevor* die
Wi-Fi-Direct-Verbindung aufgebaut wird der Fernseher meldet sich nämlich
sofort, wenn die Gruppe steht. Zusätzlich wird die Gegenrichtung versucht,
falls ein Gerät es andersherum erwartet.
Eine Einschränkung bleibt: Sich per `setWfdInfo` als Wi-Fi-Display-Quelle
anzukündigen, verlangt `CONFIGURE_WIFI_DISPLAY` eine Signaturberechtigung,
die nur Systemapps bekommen. Die App verbindet sich deshalb als gewöhnliches
Wi-Fi-Direct-Gerät. Fernseher, die auf dieses Kennzeichen bestehen, lehnen
dann ab; tolerante Geräte nehmen die Verbindung an.
Deshalb steht der Weg über den systemeigenen Übertragungsdienst in der Liste
oben: Er nutzt genau den Stack, den auch die Cast-Kachel des Systems benutzt,
und hat keine solche Hürde.
## Technik
| Baustein | Aufgabe |
|---|---|
| `ScreenEncoder` | MediaProjection → MediaCodec H.264, auf niedrige Latenz getrimmt |
| `Fmp4Muxer` | baut fragmentiertes MP4, das Browser über Media Source Extensions direkt abspielen |
| `TsMuxer` | MPEG-TS für VLC/Kodi/mpv |
| `WebServer` | HTTP + WebSocket, ohne Fremdbibliothek |
| `StreamHub` | verteilt an alle Zuschauer, wirft bei langsamen Geräten Rückstand weg statt zu stauen |
Ein Fragment pro Bild, Keyframe auf Anforderung bei jedem neuen Zuschauer,
Puffer im Player wird aktiv kleingehalten dadurch liegt die Verzögerung im
WLAN typischerweise bei einer knappen halben Sekunde.
## Bauen
```bash
gradle assembleRelease # Gradle 8.9, JDK 17+, Android SDK 35
gradle testDebugUnitTest -DsampleH264=<datei.h264> -DmuxOutDir=<ordner>
```
Die Tests schleusen einen echten H.264-Bitstream durch beide Muxer und holen
ihn über echte Sockets wieder ab; das Ergebnis lässt sich anschließend mit
`ffprobe` prüfen.