cat / goq
clone

turns a linux box into a private steam streaming appliance: plug in, tap your key, play from another computer

fix: reliable disconnect detection via conn.closed() + tokio::select!

dami etoile committed 5c71338
Old approach: polled recv.read() with 1ms timeout each frame. When the
client disconnected, the QUIC connection could stay half-open long
enough that the next client connected before the old one was detected,
leaving the counter stuck at 2.

New approach: spawn stream_frames as a task, race it against
conn.closed() with tokio::select!. When the connection closes (from
either side), the closed() future resolves immediately, the stream task
is aborted, and fetch_sub fires right away. No polling, no timing gap.
commit
5c71338ea3d392741563c2317a9c9df6cf8b7a24
parent
e662dfb91d35fbc56126d34b43cedb49e8b2797b
author
dami etoile <dami.etoile@gmail.com>
2 files changed, +32 -10
MREADME.md23+++++++++++++++--------
Msrc-tauri/src/commands.rs19+++++++++++++++++--
M README.md +15 -8
@@ -4,7 +4,9 @@ A native remote desktop app secured by FIDO2 hardware keys. Plug in a Google Tit
44 55 ## Status66 7-Early prototype. Core functionality works (identity derivation, streaming, input). Performance optimization in progress. Current frame rate is ~1–2 fps. The main bottleneck is openh264 software encoding on the host and lack of hardware decode on the client when WebCodecs is unavailable.7+Early prototype. Core functionality works (identity derivation, streaming, input). Current frame rate is ~28 fps with ffmpeg+NVENC (was ~1–2 fps with xcap+openh264 software encoding). The bottleneck has moved from host-side encoding to network/relay throughput and client-side decode.8+9+Codec and encoder backend are configurable in the info panel — H.264, H.265, and AV1 are all supported, with backends for NVENC, VAAPI, QSV, AMF, VideoToolbox, and software. The frontend uses WebCodecs for hardware-accelerated decode of all three codecs.810 911 ## How it works1012
@@ -18,18 +20,20 @@ The connection is end-to-end encrypted by Iroh. The key never leaves the hardwar
1820 1921 ## Architecture2022 21-```text23+```2224 +--------------------------- keyhome (Tauri v2) ---------------------------+2325 | |2426 | Frontend (vanilla JS, no npm) |2527 | - connection state, video canvas, input capture |28+| - WebCodecs decode (H.264/H.265/AV1, hardware-accelerated) |2629 | |2730 | Tauri IPC |2831 | |2932 | Rust backend |30-| - FIDO2 CTAP via ctap-hid-fido2 - Screen capture via xcap |31-| - Iroh Endpoint (P2P, relay, E2EE) - H.264 encoding via openh264 |32-| - OS keyring for identity - Input injection via enigo |33+| - FIDO2 CTAP via ctap-hid-fido2 - Screen capture+encode: ffmpeg |34+| - Iroh Endpoint (P2P, relay, E2EE) (NVENC/VAAPI/QSV/AMF/VT) |35+| - OS keyring for identity - Fallback: xcap + openh264 |36+| - Input injection via enigo - Codec: H.264/H.265/AV1 |3337 | |3438 +----------------------------------+--------------------------------------+3539 |
@@ -37,7 +41,8 @@ The connection is end-to-end encrypted by Iroh. The key never leaves the hardwar
3741 v3842 +------------------------------ Host -------------------------------------+3943 | - Iroh Endpoint (identity from keyring) |40-| - xcap screen capture → openh264 H.264 encode |44+| - ffmpeg screen capture → H.264/H.265/AV1 encode (hardware) |45+| - Fallback: xcap capture → openh264 software encode |4146 | - enigo mouse/keyboard injection |4247 +-------------------------------------------------------------------------+4348 ```
@@ -48,8 +53,10 @@ The connection is end-to-end encrypted by Iroh. The key never leaves the hardwar
4853 | Backend | Rust |4954 | P2P transport | Iroh (relay-assisted, end-to-end encrypted) |5055 | Hardware auth | FIDO2 CTAP via `ctap-hid-fido2` |51-| Screen capture | `xcap` |52-| Video encoding | `openh264` (software) |56+| Screen capture + encoding | `ffmpeg` subprocess (NVENC/VAAPI/QSV/AMF/VideoToolbox) |57+| Fallback capture + encoding | `xcap` + `openh264` (software) |58+| Video codecs | H.264, H.265, AV1 (configurable) |59+| Client-side decode | WebCodecs (hardware-accelerated, all three codecs) |5360 | Input injection | `enigo` |5461 | Identity storage | OS keyring |5562 | Frontend | Vanilla JS (no npm, no build step) |
M src-tauri/src/commands.rs +17 -2