SignalRC WebRTC
Der DDC-Truck, Teil 3
WebRTC ist der Baustein, der dafür sorgt, dass sich ein nicht perfektes LTE-Netz für unser SignalRC-Projekt – die Steuerung des DDC-Trucks, den wir im Artikel „SignalRC – in Echtzeit ans Steuer“ [1] ausführlich vorgestellt haben – trotzdem brauchbar anfühlt. Es löst die Probleme mit dem Netzwerk zwar nicht, arbeitet aber um die meisten ziemlich gut herum.
Was ist WebRTC eigentlich?
WebRTC steht für Web Real-Time Communication. Es ist ein Protokoll-Stack für Echtzeitkommunikation. Ursprünglich wurde es für Audio- und Videoanrufe im Browser entwickelt. Daher eignet es sich hervorragend für unsere Anwendung, denn am Ende machen wir mit unserem Fahrzeug genau das: einen Videocall. Dass die Frames überhaupt ankommen, ist an der Stelle wichtiger, als dass sie perfekt ankommen.
Technisch basiert WebRTC auf UDP. Das bedeutet:
- Pakete dürfen verloren gehen.
- Es gibt keine garantierte Reihenfolge.
- Es wird nicht auf alte Daten gewartet.
Genau das ist für Echtzeitanwendungen ein riesiger Vorteil.
Warum ist WebRTC für SignalRC so interessant?
LTE liefert uns nahezu unendliche Reichweite, aber keine übermäßige Stabilität. Bandbreite und Latenz ändern sich ständig, je nach Standort und Tagesform des nächsten Empfangsturms. Andere Streaming-Protokolle gleichen das durch Pufferung aus, um nichts an der Qualität des Streams zu verlieren. Das ist aber nicht der Fokus für uns. Wir brauchen das Bild zeitnah.
Für SignalRC ist entscheidend:
- Das Bild soll möglichst aktuell sein.
- Verzögerung ist schlimmer als Bildfehler.
WebRTC erfüllt genau diese Anforderungen, und es gibt bereits quelloffene Implementierungen. Wir müssen es also nicht komplett selbst bauen.
Ende-zu-Ende Latenz – der entscheidende Punkt
Um unser Fahrzeug sicher steuern zu können, ist es für uns entscheidend, wie viel Zeit zwischen Aufnahme und Anzeige vergeht, also für folgende Schritte:
- Kamera-Aufzeichnung
- Encoding
- Metadaten anhängen
- Transport durchs LTE-Netz
- Decoding
- Darstellung im Browser
WebRTC fügt hier kaum zusätzliche Verzögerung hinzu. Bei gutem LTE landet man realistisch bei etwa 80 bis 120 ms Gesamtlatenz. Bei schlechtem Empfang steigt sie zwar etwas an, aber das ist bis zu einem gewissem Grad hinnehmbar. Es gilt: Lieber ein bisschen Latenz hinzufügen oder ein paar Frames nur halb haben, als das Video ganz zu verlieren.
Die Rolle des Servers
Auch wenn WebRTC Peer-to-Peer arbeitet, kommt man ohne Server nicht aus:
- Keine eingehenden Verbindungen hinter LTE
- Signalisierung (SDP, ICE)
- NAT-Traversal über STUN/TURN
Der Server ist dabei nur Vermittler. Der eigentliche Medienstrom soll möglichst direkt zwischen Fahrzeug und Web-Client laufen.
ICE, STUN und TURN sind die Bausteine, die WebRTC überhaupt erst über Mobilfunk und andere restriktive Netze hinweg nutzbar machen. Ohne sie wäre eine direkte Verbindung zwischen Fahrzeug und Browser in den meisten Fällen gar nicht möglich. Dazu nun ein keiner Exkurs. Ich möchte euch aber nicht unnötig tief in das Rabbithole dahinter stoßen, denn das ist im Detail schon komplex.
ICE – Hmm ... lecker!
ICE (Interactive Connectivity Establishment) ist der übergeordnete Mechanismus. ICE sammelt alle möglichen Wege, über die sich zwei Endpunkte erreichen könnten, und testet diese gegeneinander. Ziel ist es, den direktesten und stabilsten Pfad mit der geringsten Latenz zu finden. Für SignalRC ist das entscheidend, weil sich die Netzbedingungen durch LTE ständig ändern können.
STUN – Paralysiert? Ganz im Gegenteil ...
STUN (Session Traversal Utilities for NAT) dient dazu, die von außen sichtbare Adresse eines Clients zu ermitteln. Das Fahrzeug kennt intern nur seine private IP; über STUN erfährt es, unter welcher öffentlichen Adresse und welchem Port es im Mobilfunknetz erreichbar ist. In einfachen Fällen reicht das bereits aus, um eine direkte Peer-to-Peer-Verbindung aufzubauen. STUN verursacht praktisch keine zusätzliche Latenz und ist daher immer der bevorzugte Weg.
TURN – Um den Bogen zu schließen ...
TURN (Traversal Using Relays around NAT) ist die Rückfallebene. Wenn eine direkte Verbindung aufgrund strenger NATs oder Firewalls nicht möglich ist, wird der gesamte Datenverkehr über einen TURN-Server geleitet. Das ist funktional zuverlässiger, aber auch teurer und langsamer, da jedes Paket einen zusätzlichen Hop macht. Man kommt bei einer Installation auf einem Cloud Server nicht drum herum. Denn dieser soll auch abgeschottet sein, und genau das stellt SignalRC vor entsprechende Herausforderungen. Im WLAN ist es gar kein Problem ohne.
Alles zusammen
In Kombination sorgen ICE, STUN und TURN dafür, dass sich Fahrzeug und Web-Client selbst über LTE-Netze finden, eine Verbindung aufbauen und diese bei wechselnden Bedingungen aufrechterhalten können. Sie sind damit eine Grundvoraussetzung dafür, dass WebRTC im SignalRC-Projekt zuverlässig funktioniert.
Fußnote zu Video und Steuerdaten
SignalRC nutzt zwei unterschiedliche Datentypen:
- Video: kontinuierlich, verlusttolerant
- Steuerung: klein, häufig, zeitkritisch
Alles was zur Übertragung von Video und Audio beiträgt läuft über WebRTC, weil das genau die Probleme löst, die oben beschrieben wurden.
Die gesamte Kontrolle und Telemetrie ist nicht darüber abgebildet, auch wenn WebRTC dafür Kanäle anbietet. Hier war die einfache Integrierbarkeit vorrangig. Daher ist es SignalR. Von der Latenz und Paketgröße für die Nachrichten steht SignalR den WebRTC Channels in nichts nach.
Umsetzung in SignalRC
SignalRC benutzt einen Janus WebRTC Server und MediaMTX auf dem Client. Beide Komponenten sind Open Source.
Janus Gateway
Janus ist eine Implementierung eines WebRTC-Servers. Es hat einen recht kleinen Fußabdruck und eignet sich daher hervorragend für unser Projekt.
Janus dient als WebRTC-Gateway zwischen Fahrzeug und Web Client. Es vermittelt den Videostream, ohne selbst Encoder oder Player zu sein.
Das Streaming-Plug-in übernimmt die Weiterleitung eines per RTP eingespeisten Streams an WebRTC-Konsumenten.
Server
Der SignalRC Server Dienst startet beim Hochfahren einen eigenen Janus-Prozess und loggt dessen Ausgaben im Server Log. Das lässt sich zwar mit der Einstellung RunJanusServer deaktivieren, ist aber nur nötig, wenn man plant, einen abgekoppelten Janus-Server zu nutzen. Weiterhin können der Hostname sowie der UDP-Portbereich fürs Streaming festgelegt werden. Beim Verbindungsaufbau wird jedem Fahrzeug ein freier Janus-UDP-Port zugewiesen und an das Fahrzeug zurückgegeben.
Janus wird bei der Installation aus GitHub geholt und kompiliert. Das Skript reduziert den Build mit WebSocket- und Streaming-Plug-in auf benötigte Module.
Onboard
Auf der Seite des Fahrzeugs verbindet es sich per SignalR, ruft OpenCarConnection auf und erhält vom Server den Janus-Host inklusive des ihm zugewiesenen UDP-Ports. Dieser wird auch im Server und Onboard Client gespeichert und nur bei einem Neustart der Verbindung neu ausgehandelt. Der Videostreaming-Service wird bei Änderungen an den serverseitigen Einstellungen vom Server benachrichtigt und danach mit den neuen Informationen reinitialisiert.
Hier kommt zusätzlich noch MediaMTX zum Einsatz um den Stream für Janus mit Metadaten zu versorgen. Dazu gleich mehr.
Client (Web-UI)
Der Client initialisiert einen Janus-Client im Browser, bindet janus.plugin.streaming ein, listet verfügbare Streams des Fahrzeugs und startet das Abonnement des ersten Streams. Der Videostream landet anschließend in einem video-Element.
Um die weitere Behandlung des Streams kümmert sich der Janus-Client.
Zusammenspiel
- Der Server kompiliert oder startet Janus und verteilt Host plus Port an Fahrzeuge.
- Das Fahrzeug codiert das Kamerabild in MPEG-Stream und sendet per RTP über MediaMTX an Janus.
- Der Browser-Client verbindet sich via HTTP oder WebSocket mit Janus, holt den Stream ab und rendert ihn im Browser. (Wie genau, kontrolliert der Janus Server.)
MediaMTX Onboard
Der Onboard-Client startet den MediaMTX-Prozess und überwacht dessen Ausgabe. Die Binaries für MediaMTX sind im Projekt enthalten. Die Konfiguration nutzt die rpiCamera-Quelle, setzt Auflösung sowie Bitrate und ruft ffmpeg im runOnInit-Hook auf, um den lokalen RTSP-Stream als RTP nach Janus durchzureichen. Die Einstellungen werden vom Onboard-Client angepasst. So gibt es abgesehen vom ProzessInfo im Client keine Referenz auf MediaMTX selbst.
Warum muss das sein? MediaMTX stellt damit eine robuste Capture- und Streaming-Pipeline zur Verfügung. Es liest direkt von der Raspberry-Pi-Kamera, erzeugt Metadaten für WebRTC-Endpoints und startet ffmpeg neu, falls der Prozess aus irgendwelchen Gründen endet. Das erspart uns die Konfiguration der Metainformation in ffmpeg und macht die gesamte Videoübertragung deutlich stabiler. Warum auch selbst bauen, wenn das schon jemand für uns gemacht hat?
Der Prozess wird nach dem Beenden des Onboard-Clients ebenfalls beendet, sodass der Raspberry Pi nicht mehr sinnlos die Kameradaten aufnimmt.
Bei Bedarf kann mit der Config von MediaMTX auch eine Aufzeichnung oder Ähnliches gemacht werden. Den Stream abzufangen und ihn in Kopie wegzuschreiben ist damit ebenfalls kein Problem.
Schlusswort
WebRTC ist ein großartiges Tool, das sich im Werkzeugkasten zu haben lohnt. Man muss auch nicht alle Details davon verstehen. Es hilft aber ungemein, wenn man dessen Basics schon mal gehört hat, damit man weiß, wie man anfängt. Als ich meine Recherche zu dem Thema gestartet habe, war ich erst mal etwas erschlagen, weil ich dachte: Alle möglichen Apps können Video in Realtime übertragen. Das funktioniert eben auch super mit WebRTC. Dank der Tools, die es schon gibt, ist es auch für jemanden umsetzbar, der nicht unendlich tief im Thema drinsteckt.
Ich hoffe, dass euch mein Einsatz der Technologie inspiriert und ihr daraus auch coole Anwendungsfälle machen könnt.
[1] Georg Poweleit, SignalRC – in Echtzeit ans Steuer, dotnetpro 10-11/2025, Seite 46 ff.
- Was ist WebRTC eigentlich?
- Warum ist WebRTC für SignalRC so interessant?
- Ende-zu-Ende Latenz – der entscheidende Punkt
- Die Rolle des Servers
- ICE – Hmm ... lecker!
- STUN – Paralysiert? Ganz im Gegenteil ...
- TURN – Um den Bogen zu schließen ...
- Alles zusammen
- Fußnote zu Video und Steuerdaten
- Umsetzung in SignalRC
- Janus Gateway
- MediaMTX Onboard
- Schlusswort