Files
punktfunk/clients/probe
enricobuehlerandClaude Fable 5 4a01bc4463 feat(core+host+client): cursor channel — remote-desktop sweep M2a+M2b
The host cursor stops riding the video and becomes a real OS cursor on
the client (the Parsec/RDP model): pointer feel no longer pays the
capture→encode→network→decode→present round trip.

Wire (M2a):
- Hello grows a client_caps trailing byte (CLIENT_CAP_CURSOR) after the
  fixed display_hdr block — presence disambiguated by remaining length,
  which caps the post-HDR tail at 27 bytes (documented); Welcome answers
  HOST_CAP_CURSOR (capable-and-asked, the 444/clipboard precedent).
- CursorShape (0x50, control stream): serial + dims + hotspot + straight
  RGBA, ≤120px/side so the u16 frame always fits (128² would overshoot);
  client caches by serial — re-showing a known shape costs 14 bytes, not
  a bitmap (RDP pointer-cache for free).
- CursorState (0xD0 datagram): serial + visible/relative_hint flags +
  position, sent once per encode-loop tick — latest-wins, self-healing
  under loss, no refresh timer. relative_hint is reserved for M3.
- Client core: two new planes (control-task + datagram-task arms) →
  next_cursor_shape/next_cursor_state; connect() grows client_caps
  (C ABI passes 0 until the v11 cursor poll fns exist).

Host (M2b, Linux portal only):
- handshake::cursor_forward is THE predicate (client asked ∧ Linux ∧
  compositor ≠ gamescope) — Welcome bit and session wiring both read it.
- SessionPlan.cursor_blend goes false for a forwarding session; the
  encode loop ticks a CursorForwarder every iteration: shape-serial diff
  → control-task bridge (mirrors probe_result), state datagram → conn.
- CursorOverlay/capture CursorState carry the hotspot through
  (nearest-neighbor downscale backstop for XL cursors, unit-tested).

Presenter:
- CursorChannel drains both planes per loop iteration; shapes become
  SDL color cursors (from_surface + hotspot), applied while the desktop
  mouse model is engaged; visibility follows the host; capture/released
  hands back the system cursor. Sessions advertise the cap when they
  START in desktop mode.

Verified on .21: fmt + clippy -D warnings (7 crates) + tests green
(core 218 incl. new wire roundtrips, host 245 incl. e2e + forwarder
downscale tests).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 23:43:23 +02:00
..

punktfunk — probe (reference client)

punktfunk-probe is the headless reference client for the punktfunk/1 protocol — a command-line tool for testing, latency measurement, and validating host behavior. It's not a streaming app you'd watch on; it connects, exercises a plane, and reports numbers. If you want to actually stream, use the Linux, Windows, Apple, or Android clients.

Because it links the same punktfunk-core as every other client, it's also the canonical example of driving the protocol end to end: QUIC control plane, UDP data plane, and the side planes (input, audio, rumble) over QUIC datagrams.

What it does

  • Receives a real stream, writes a playable elementary stream (.h265/.h264/.av1 — the extension tracks the negotiated codec; the probe advertises all three and the host picks), and reports per-frame capture→received latency percentiles (the host stamps each frame with its capture clock).
  • Verification mode against a synthetic host — byte-checks deterministic test frames.
  • Exercises every plane with scripted test traffic: --input-test (mouse/keyboard), --mic-test (a 440 Hz Opus tone up to the host mic), --touch-test (a synthetic finger), --rich-input-test (DualSense touchpad + motion, logging the HID-output feedback that comes back).
  • Trust--pin <64-hex> pins the host fingerprint; --pair <PIN> runs the SPAKE2 pairing ceremony and prints the verified fingerprint to pin from then on. Without a pin it trusts on first use.
  • Discovery--discover [secs] browses the LAN for _punktfunk._udp hosts and prints each (name, addr:port, pairing requirement, cert fingerprint), then exits.
  • Negotiation knobs--mode WxHxFPS, --remode (mid-stream mode change), --bitrate, --codec auto|h264|hevc|av1 (preference; the host resolves), --audio-channels (stereo / 5.1 / 7.1), --compositor, --gamepad, --launch, --speed-test. Env: PUNKTFUNK_CLIENT_10BIT=1 / PUNKTFUNK_CLIENT_444=1 advertise the 10-bit / 4:4:4 client caps (for testing a host's PUNKTFUNK_10BIT/PUNKTFUNK_444).

Usage

# stream 720p120 from a host, save the video, and print latency percentiles:
cargo run -p punktfunk-probe -- --mode 1280x720x120 --connect HOST:PORT --out /tmp/a.h265

# list hosts on the LAN:
cargo run -p punktfunk-probe -- --discover

# pair with a host that requires it (read the PIN off the host), then stream:
cargo run -p punktfunk-probe -- --connect HOST:PORT --pair 1234
cargo run -p punktfunk-probe -- --connect HOST:PORT --pin <64-hex> --input-test

Full flag reference is in the module doc-comment at the top of src/main.rs.

  • Project README — the host, the streaming clients, and the protocol
  • punktfunk-host punktfunk1-host — the persistent native-protocol listener to probe against (see the "Running on this box" section of the repo README / CLAUDE.md)