Expand description
Closed-loop rate control inside the QoS ceiling (PLAN.md §1.3).
A pure, deterministic controller stepped once per second with what the
transport and the pilot measured. It never exceeds the profile ceiling and
never goes below 25 % of it; it moves the request to the publisher
(video-config) and Seyd’s own FEC rates.
Rules, in priority order:
- FEC follows measured loss, burst-first. Cellular loss arrives in
bursts, and a block of 8 data chunks with
k = 1(the 15 % default) dies to any burst of two. So the first response to any measurable loss (≥ 0.2 % over the last 5 s) isk = 2(25 %), thenk = 3at ≥ 2 % (38 %) andk = 4at ≥ 5 % (50 %). Keyframe parity is at least delta + 10 (they are larger and losing one costs a GOP). FEC steps up immediately and steps down one level only after 5 clean seconds. - Raising FEC is paid for by the video rate. The link constrains
total bytes, so the bitrate request is scaled by
(1 + profile_fec) / (1 + fec)— the on-wire budget stays what the profile promised. - Residual loss (≥ 2 frames/s genuinely lost after FEC — timed-out frames whose chunks arrived late are jitter and are not counted) without any latency signal is a loss problem, not a congestion problem: step FEC up one level instead of cutting the rate (measured: cutting on residual loss alone sawtooths 25 % down / 10 % up forever on a lossy-but-uncongested link). Only when FEC is already at its top level does residual loss cut the bitrate.
- Congestion: AIMD with latency gating. A backlog drop is the primary
signal and cuts 25 % at once. Latency is secondary: the median of the
last 3 RTT samples must exceed
min_rtt + budget/2for 2 consecutive seconds, and the sample right after a keyframe went out is ignored (on a ~1.5 Mbps uplink a 45 KB IDR is 240 ms of queue by itself — measured as 80–94 ms RTT spikes that used to trigger cuts). Raise 10 % after 5 consecutive clean seconds. Cuts are at most one per 5 s. - Emission hysteresis. A bitrate decision is emitted at most every
5 s and only for ≥ 10 % changes (encoders hate churn); FEC changes are
emitted as soon as they happen; FEC steps down one level only after
10 clean seconds. A
steadydecision never moves the bitrate: the reason that moved the target is carried until it is emitted. - At the floor and still congested for 5 s →
suggested_fps = 15.
Structs§
Functions§
- effective_
ceiling_ kbps - The profile’s ceiling, lowered to the publisher’s own maximum when the host declared one (0 = none).