forked from unom/punktfunk
The host's recovery-cadence detector warns that "client keyframe recoveries are METRONOMIC — a periodic host/display disturbance (display-topology churn, display-poller software, virtual-display timing) is the likely cause, not random network loss". In a 2026-08-13 field log it fired at period_s=2.0 and sent the investigation at three innocent host subsystems. 2.0 s is `punktfunk_core::client::FLUSH_COOLDOWN`. The client's receive-backlog guard sheds a standing queue with a flush plus a keyframe request and is rate-limited to one per cooldown, so a client that cannot sustain the stream asks for a keyframe at EXACTLY that spacing for as long as it stays behind — the constant's own doc says it "degrades into a periodic skip + a logged warning", which is the behaviour the detector then read as physical. Perfect periodicity argues FOR a fixed software cooldown, not against it. In the field case the host was blameless and the chain ran the other way: the client refused the negotiated codec on its Vulkan rung, demoted to a slower decode path, could not hold 4K120 there, and built the standing queue. Three layers between the symptom the host reported and the cause. So the detector now routes: a period on the client's cooldown names the client and says where to look in ITS log (`receive backlog stopped draining`, and a demoted decode rung); anything else keeps the display-disturbance wording it had. The comparison reads FLUSH_COOLDOWN itself — now `pub` for exactly this, documented as such — rather than a copy of the number, so the two cannot drift. ±10 % absorbs scheduling jitter and the request's trip without being wide enough to swallow the disturbance cadences the other branch exists to report. Verified: 18/18 native::stream::tests on linux/amd64 (container), including the new case, which derives its inputs from FLUSH_COOLDOWN so it survives a retune; clippy --all-targets -D warnings clean; cargo check clean on the Windows CI runner.
punktfunk-core
The shared protocol core — the one place where punktfunk's transport, forward error correction, and crypto live. It's linked into the host and every native client, so there's exactly one implementation of the wire format everywhere.
Written in Rust with no async on the per-frame path (native threads only). It exposes both a normal Rust API and a stable, versioned C ABI, so the Swift and Kotlin clients — and any C embedder — link the same code as the Rust ones.
What's in here
- Transport & session (
session.rs,transport/,packet.rs) — thepunktfunk/1data plane over raw UDP: packetization, reassembly (with attacker-bounded limits), pacing, and socket tuning. - FEC (
fec/) — the wall-breaker. Two codes:- GF(2⁸) classic Reed–Solomon with the Cauchy generator matrix — byte-identical to the
nanorslibrary Moonlight uses, so our parity is decodable by a stock Moonlight client. - GF(2¹⁶) Leopard-RS (SIMD, O(n log n)) — up to 65535 shards/block, which removes the ~1 Gbps
FEC ceiling.
punktfunk/1negotiates this one.
- GF(2⁸) classic Reed–Solomon with the Cauchy generator matrix — byte-identical to the
- Crypto (
crypto.rs) — AES-128-GCM session encryption with per-direction nonce salts and sequence-as-AAD; SPAKE2 PIN pairing lives behind thequicfeature. - QUIC control plane (
quic.rs,client.rs, featurequic) — the Hello/Welcome/Start handshake, cert pinning/TOFU, reverse audio, and the embeddableNativeClientconnector. This is the only placetokio/quinnare allowed; the feature is off by default so the core stays runtime-free. - C ABI (
abi.rs) — the versioned surface (punktfunk_abi_version(),PunktfunkConfigcarrying its ownstruct_size) that generatesinclude/punktfunk_core.hvia cbindgen at build time.
Build outputs
The crate builds three ways at once (crate-type = ["lib", "cdylib", "staticlib"]):
| Output | Used by |
|---|---|
lib (rlib) |
the host, probe, and tools link it as a normal Rust crate |
cdylib (.so/.dylib) |
the Swift / Kotlin clients via the C ABI |
staticlib (.a) |
the C test harness and static embedding |
Test
cargo test -p punktfunk-core # unit + proptest + loopback
cargo run -p loss-harness # FEC loss-resilience sweep (no network needed)
bash crates/punktfunk-core/tests/c/run.sh # standalone C-ABI link + round-trip proof
Design invariants (do not regress)
- One core, linked everywhere — protocol/FEC/crypto live only here, behind the stable C ABI.
- No async on the hot path — the per-frame pipeline is native threads only;
quic(tokio/quinn) is control-plane only, feature-gated, off by default. - Security hardening stays intact — the reassembler bounds attacker-controlled fields before
allocating; AES-GCM keeps per-direction nonce salts + seq-as-AAD; the ABI checks
struct_size. Regression tests exist — keep them green.
Related
punktfunk-host— the streaming host built on this core- Clients — the apps that link this core over the C ABI (or directly, in Rust)
- punktfunk-planning:
implementation-plan.md(internal planning repo) — why GF(2¹⁶) FEC, the latency budget, and the architecture thesis