Root-caused live on a phone at 100 Mbps (stream stuck seconds behind, then
oscillating): a stack of transport defects, each amplifying the next.
- MTU-safe shards: shard_payload 1452 overshot the IPv4/1500 budget (the old
math forgot the 40 B header + 24 B crypto ride inside the UDP payload and
counted IP+UDP as 8 B) — the kernel silently split EVERY video datagram into
two IP fragments, doubling per-datagram loss on Wi-Fi. New
config::mtu1500_shard_payload() = 1408 (1472 sealed = the exact ceiling),
negotiated in the Welcome, pinned by a unit test.
- Android batched I/O: recv/send batching was cfg(linux); Android is
target_os="android" and silently fell back to a syscall per datagram. The
libc crate binds neither recvmmsg/sendmmsg nor mmsghdr for Android, so a
local bionic extern binding provides them (API 21+, floor is 28); cbindgen
excludes them from the C header. The pump/runtime threads also get the
Apple-QoS analogue on Android: nice −8 (below the decode thread's −10).
- Latency-bounded receive: packets are consumed strictly in order at exactly
the arrival rate, so a standing queue (Wi-Fi stall, power-save clumping)
NEVER drains — observed as a stream permanently 6-7 s behind with both 32 MB
socket buffers full. The pump now flushes the entire backlog
(Session::flush_backlog: discard ring + kernel queue at memcpy speed, reset
the reassembler) and requests a keyframe when frames keep completing > 400 ms
behind the skew-corrected capture clock (30 consecutive, 2 s cooldown,
logged).
- Time-based loss window: the reassembler declared an incomplete frame lost a
fixed 4 INDICES behind the newest — 33 ms at 120 fps, inside normal Wi-Fi
retry/reorder timescales, so merely-late frames were pruned every few
seconds, each costing a recovery-IDR burst + an inflated loss report.
Now 120 ms of capture time (LOSS_WINDOW_NS), same fuse at every refresh
rate, with a 64-index hard cap bounding memory against hostile pts.
- Adaptive-FEC hysteresis: the controller was memoryless — one clean 750 ms
report dropped FEC from 8 % straight back to the 1 % floor, so periodic burst
loss (Wi-Fi scan / BT coexistence beats) always hit an unprotected stream and
ping-ponged 1↔8 % with a frozen frame per cycle (observed in the host log as
alternating loss_ppm=0/50000). Attack stays instant; decay is now one point
per clean report.
Verified: full core suite (incl. new flush + time-window tests) on macOS +
Linux, host release build, arm64 cargo-ndk build, and a 30 s wired probe run
at 2800x1260@120 — 3559/3559 frames, zero loss, capture→received p50 5.3 ms
(host 5.1 + network 0.3).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GPU-free, so they run in normal CI. Two layers: crypto/{seal,seal_in_place,open} on one MTU shard,
and pipeline/{gf8,gf16}/{64KB,1MB} — a whole frame through the real per-frame path end to end over
the loopback transport (FEC encode → AES-GCM seal → packetize → reassemble → FEC decode → open).
Baselines on the dev box (RTX 5070 Ti VM): AES-GCM ~1.57 GiB/s/shard; gf16 ~418 MiB/s at 1 MB vs
gf8 ~23 MiB/s (the GF(2^8) O(n^2) ceiling the GF(2^16) Leopard wall-breaker removes — exactly the
kind of regression this should catch). The GPU capture/NVENC path is out of scope here (Tier 3).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>