Add Gamer Mode: low-latency WebRTC streaming via webrtcbin#220
Add Gamer Mode: low-latency WebRTC streaming via webrtcbin#220anagnorisis2peripeteia wants to merge 2 commits into
Conversation
Replaces the ustreamer + Janus pipeline with a direct GStreamer pipeline for minimum-latency 1:1 video streaming: v4l2src -> v4l2h264enc (hw) or x264enc (sw fallback) -> rtph264pay -> webrtcbin Key differences from the Janus path: - No SFU middleman (direct P2P WebRTC) - No jitter buffers (latency=0 on webrtcbin) - Zero-latency H.264 encoding (tune=zerolatency) - Auto-detects Pi hardware encoder, falls back to software Components: - contrib/gamer-mode/gamer_streamer.py: standalone GStreamer + signaling server - kvmd/apps/kvmd/streamer/gamer.py: kvmd subprocess manager - web/share/js/kvm/stream_webrtc.js: browser WebRTC client (no Janus lib) - web/share/js/kvm/stream.js: added "webrtc" mode to stream selector
- streamer.mode config option ("default" | "gamer"). When "gamer", kvmd
instantiates GamerStreamer instead of the ustreamer-backed Streamer.
streamer.gamer.{device,fps,bitrate} configures the pipeline.
- GamerStreamer now spawns the gamer_streamer.py subprocess and bridges
JSON-line signaling over its stdin/stdout. The standalone HTTP server
/ embedded HTML page mode (--port) is preserved for development.
- New /ws event "webrtc_signal" relays SDP / ICE frames between the
browser and the GamerStreamer subprocess. The frontend client uses
kvmd's /ws (no separate connection on a sidecar port).
- V4 mux signal-loss recovery: the pipeline now feeds an input-selector
between live v4l2 capture and a videotestsrc black-frame fallback.
A bus error from v4l2src (e.g. EDID renegotiation during a port
switch) swaps to the fallback without tearing down the WebRTC
session; a recovery timer polls the capture branch and swaps back
when the signal returns. The browser sees signal_lost/signal_restored
signaling frames in the meantime.
|
Did you do any test about latency difference between Janus and GStreamer's webrtcbin based implementations? |
|
Hi. For things like this, I would prefer that you contact me - I'm open to communication and discussion of issues and available in the Discord public chat. We have invested a lot of time in latency research issues and outlined the main points in the article: https://docs.pikvm.org/latency. I recommend that you take a step back and explore it. Because some of the assumptions that your PR is based on seem wrong to me. In particular, there is no jitter buffer in Janus. The listed H.264 optimizations have been used for a long time. Anyway, as a justification for this PR, I would like to see a benchmark. You are introducing a huge layer of new code where it would be possible to do a spot optimization of existing components. We did a lot, but we could still have missed something, and a contribution in this direction would be more useful than adding a completely alternative backend. |
Gamer Mode: Low-Latency WebRTC Streaming
Direct WebRTC streaming mode that bypasses the Janus SFU entirely, using GStreamer's
webrtcbinfor a 1:1 P2P connection between the Pi and the browser.Why
Current pipeline (ustreamer -> Janus -> browser) adds latency through Janus's jitter buffers and SFU processing. For single-user / gaming scenarios that overhead is unnecessary.
How to enable
Then select "WebRTC" in the stream mode picker.
Components
contrib/gamer-mode/gamer_streamer.py: GStreamer pipeline + signaling. Two transports:--port Nstandalone (built-in aiohttp server + embedded HTML, for development).--port) stdio JSON-line frames, used when kvmd parents the process.kvmd/apps/kvmd/streamer/gamer.py:GamerStreamersubprocess manager. Spawns the script, reads stdout for SDP / ICE / signal events, writes browser responses to stdin.kvmd/apps/_scheme.py:streamer.mode+streamer.gamer.*config options.kvmd/apps/kvmd/__init__.py: branch onstreamer.modeat startup.kvmd/apps/kvmd/server.py:webrtc_signalWebSocket event handler bridging browser <-> subprocess.web/share/js/kvm/stream_webrtc.js: browser-side WebRTC client (nativeRTCPeerConnection, no Janus lib). Signaling rides on the existing/ws.web/share/js/kvm/stream.js: "webrtc" stream-mode entry.Latency optimisations
latency=0onwebrtcbin(no jitter buffer)tune=zerolatency/speed-preset=ultrafaston x264enc fallbackconfig-interval=-1on RTP payloader (SPS/PPS with every keyframe)v4l2h264enchardware encoder; falls back tox264enconly when absentV4 multi-port switch handling
The pipeline uses an
input-selectorwith a livev4l2src(sink_0) and avideotestsrc pattern=black(sink_1). A bus error from the capture source (e.g. EDID renegotiation during a port switch) flips the selector to the black branch without tearing down the encoder or the WebRTC session. A recovery timer polls the capture branch every second and swaps back as soon as the device returns to PLAYING. The browser receivessignal_lostandsignal_restoredframes in the meantime.What is NOT yet done
v4l2h264encpath is auto-selected but unverified)Dependencies
webrtcbin)gi.repository.Gst,GstSdp,GstWebRTC)--portmode)