• v0.13.0 7c6821b4ad

    v0.13.0 — the seat survives its own streamer
    All checks were successful
    CI / build-and-test (push) Successful in 2m27s
    Release / build-and-test (push) Successful in 1m8s
    Release / release-image (push) Successful in 4s
    Stable

    gabrielgad released this 2026-08-08 15:50:03 -04:00 | 3 commits to main since this release

    placeholder, replaced below

    Downloads
  • v0.9.2 10e3597b04

    gabrielgad released this 2026-07-03 06:26:30 -04:00 | 212 commits to main since this release

    seat-streamer now refuses to pair WebRTC media across the WireGuard mesh: mesh-subnet candidates (default 10.0.0.0/24,fd00::/64, override with GSE_ICE_EXCLUDE) are neither signalled to viewers nor accepted from them. Mesh-peer viewers previously formed host pairs through the tunnel — hairpinning all media via the VPS instead of going LAN-direct or through the TURN relay — regardless of relay-side denies. Viewers with a mesh VPN profile active now stream over the same clean paths as everyone else.

    Downloads
  • v0.9.1 88e3d7b5f6

    gabrielgad released this 2026-07-02 23:24:58 -04:00 | 214 commits to main since this release

    Patch on the adaptive controller: decode-cuts now remember the discovered ceiling (5 min TTL) and stop up-probing above it, instead of sawtoothing 60↔84 forever against software-decoding browsers. ceiling-hold in the adapt ack marks a capped park. Repeated cuts converge; the TTL re-probes once conditions may have changed (browser switch, thermal recovery).

    Downloads
  • v0.9.0 38f716a5d5

    gabrielgad released this 2026-07-02 23:10:39 -04:00 | 216 commits to main since this release

    The fixed-tier era is over: every seat now runs a per-viewer adaptive AIMD controller by default.

    Adaptive quality-setpoint controller (seat-streamer)

    • fps notch ladder 60→72→84→100→120→144→170→200: one notch per healthy heartbeat up, ×0.75-snap down on distress; encoder-saturation hold protects the capture export pool.
    • Decode-vs-link classifier on measured signatures: backlog slope = client decode ceiling (cut fps); unrecovered loss / jbuf blowout = link overload (cut quality). NACK/RTX recovering transient loss is the transport working — it is telemetry, not distress.
    • The controller IS the rate controller: CQP with live qp stepping. qp never chases content — a quiet scene at 0.3 Mbps and a battle at 8 Mbps at the same qp are both correct. Quality degrades only on real loss (proportional) or sustained output above the fps-coupled budget (the burst-bomb guard — vulkanh264enc exposes no HRD peak cap), and relaxes toward the setpoint on healthy heartbeats. (RADV's hardware VBR undershoots its target >2× on real content and starves P-frames — unusable for this.)
    • Keepalive/panic/recovery: viewer silence parks the encode at the floor; recovery re-ramps, never blind-resumes.
    • Burst-flushed datachannel stats are discarded, not diffed into phantom telemetry.
    • Tuning: GSE_FPS_FLOOR, GSE_ADAPT_MBPS_PER_100FPS, GSE_ADAPT_MAX_MBPS, GSE_ADAPT_QP_BEST, GSE_ADAPT_HEARTBEAT_SECS; GSE_ADAPTIVE_FPS=0 reverts to static CQP.

    Client (ui41)

    • adapt-ack liveness → fast ka probes → buffering screen; re-ramp on recovery.
    • Delta-proportional telemetry cadence (1s steady, 400ms while correcting).
    • Decode-capability probe (mc:hw / mc:sw): detects software-decoding browsers from inside the viewer — a software decoder caps ~84fps at 1080p where the same phone does 175+ in hardware. If the overlay says mc:sw, switch to a Chromium browser or enable hardware video decoding.

    Validated

    Pixel 9 Pro Fold, 1080p, real cellular link: reached the 200 ceiling with the encoder streaming 167–175fps at 5–10 Mbps floating with scene content, quality recovering after every disturbance.

    Downloads
  • v0.8.0 ad2c4ed7d3

    gabrielgad released this 2026-07-02 20:56:30 -04:00 | 219 commits to main since this release

    Streaming quality

    • Sender pacing (deploy/paceshim): LD_PRELOAD SO_MAX_PACING_RATE shim + fq qdisc notes. Keyframe bursts that left the box at 200+Mbps instantaneous now pace at a configurable rate (default 20MB/s). Includes the fq flow_limit tail-drop gotcha writeup.
    • Real hardware VBR: rate-control engaged live post-PLAYING (GSE_HW_VBR_MBPS) — the inline pipeline-string property never actually engaged and every session silently ran CQP.
    • Truthful SDP profile-level-id injection — fixes remote clients falling into 15x-slow software decode.
    • Default jitter buffer 150ms → 30ms (ui37) — validated on real WAN viewers with pacing active: jbuf pinned 18-30ms, jitter 4-13ms.
    • tiled-modifier dmabuf negotiation in gst-dmabuf-vulkan (with RADV tiled-import workaround).

    Infra

    • gadgetd: single-owner daemon for raw-gadget Xbox-pad lifecycle; seat-streamer is now a socket client (fixes UDC races + udev uaccess race).
    • announce: Matrix seat-open notifier sidecar.
    • Element lobby widget + one-click ?seat= join.
    • admin: forward graphical env to spawned launches (fixes wedged deploys).

    Docs & tooling

    • docs/adaptive-streaming.md: AIMD adaptive fps/bitrate controller design (floor 60 / ceiling 200, delta-proportional cadence, decode-vs-link distress classifiers, panic→recovery) — next major work.
    • scripts: pcap burst analyzer, CDP video-diff harness, pad e2e/race probes, bench updates.
    Downloads
  • v0.6.0 753dd3a7b0

    gabrielgad released this 2026-06-22 21:56:27 -04:00 | 230 commits to main since this release

    Fixes

    • Silent audio fixed. The Opus track used payload type 97, which collided with the video RTX retransmission stream under BUNDLE — the browser demuxed those packets to video, so audio received zero RTP despite a negotiated, live track. Moved Opus to the standard WebRTC PT 111.
    • Touch-client audio never unmuted. The first-gesture auto-unmute ran in the bubble phase, but the on-screen sticks/buttons stopPropagation, so grabbing a control never unmuted. Moved to the capture phase.

    Stability

    • Input rate-cap (~40Hz) on the pad pump and touch abs-pointer. A dragged stick on a 120fps phone flooded the reliable+ordered SCTP datachannel (head-of-line blocking), whose send-buffer exhaustion threw association went into error state and tore down the whole bundled session every few seconds.

    Telemetry

    • Inbound-audio stats (akbps/alvl/atmute/track state) in the diag overlay and the datachannel snapshot; producer-side tap_acap/tap_aenc rates and offer-SDP media-line logging in the seat log. (Also fixes a temporal-dead-zone bug that silently killed all client telemetry.)

    Controller UX

    • Floating-stick zones confined to the bottom corners (22%×34%), freeing the rest of the screen for touch point-and-click.
    • On touch, the top bar no longer pops up during play — reveal it with a swipe down from the top edge.

    Web client build: ui36.

    Downloads
  • v0.5.0 bb9435a72e

    v0.5.0 Stable

    gabrielgad released this 2026-06-22 08:30:03 -04:00 | 233 commits to main since this release

    Floating on-screen analog sticks (touch-point centroid, ghost on release, chases the thumb) with max-sensitivity shaping; corner-anchored face buttons that don't drift on larger displays. Orchestrator viewer-WS ping/pong liveness so dead tabs free their seat automatically; POST /api/kick/:seat force-eject (token-authed) + viewer_gen race guard. Admin Eject buttons + /api/eject. Fixes a JS typo that broke admin.html.

    Downloads
  • v0.3.0 e96ec42ac0

    gabrielgad released this 2026-06-18 18:00:28 -04:00 | 243 commits to main since this release

    Vulkan zero-copy GPU-snapshot path fixed end-to-end (RADV / RX 9070 / GFX1201)

    • Crash fixedsnap_copy ran vkCmdCopyImage on the video-encode queue (family 3, VIDEO_ENCODE-only, no TRANSFER), faulting inside RADV on the first frame (gst's process-wide segtrap misreported it as an srtp plugin crash). Now runs on a graphics/transfer queue; snap images CONCURRENT across graphics+encode families.
    • Ghosting fixed — gamescope's dmabuf write-fence is imported as a binary semaphore the copy waits on, so the snapshot always reads a finished frame. Removes torn/stale-source ghosting and bitrate overspend.
    • CQP rate control — RADV's vbr/cbr ignore the bitrate target (~54 Mbps firehose); switched to CQP, QP env-tunable via GSE_CQP_QP_I/GSE_CQP_QP_P (default 28/30).

    Result (Patch Quest, 1080p200): full 200fps, idle ~3 Mbps, motion ~18-25 Mbps, ghost-free — down from a 50-91 Mbps firehose with ghosting.

    Downloads