feat(client/abr): learn the host's rate cap from short acks, and read host encode time as a signal
Two client-side halves of the §ABR-overdrive fix (the 4K120 sessions that climbed to 1 Gbps against a 794 Mbps encoder and a 8.33 ms budget): - Short-ack cap learning: the host now resolves a climb it can't serve to what the encoder actually runs at (its codec-level ceiling, or the current rate while encode is behind cadence). Two consecutive identical short acks latch that value as a host cap the climb logic folds into its ceiling — one short ack stays a transient (a failed rebuild also acks short once). The cap is mode-scoped (cleared on an accepted mode switch, tracked via a mode generation counter the control task bumps) and re-probes one step after ~60 s parked clean, so a heavy-scene refusal can't quietly cap the whole session. - Host-encode-latency down-driver: the per-AU 0xCF `encode_us` the host already ships (and the overlay already draws) now feeds the controller through its own window accumulator — the overlay channel is lossy and embedder-drained, so the ABR gets a dedicated mirror of the decode-latency path. Baseline-relative like the decode signal (an escalated host reports encode_us inflated by ~a frame of queue depth; an absolute budget threshold would read permanently red), with the baseline rebased after our own decreases so one backoff doesn't train-fire into the floor. This is the only signal that can push an already-too-high rate back under the encoder's compute knee — host climb refusal stops the climb, but nothing else descends on a clean LAN. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -224,6 +224,20 @@ pub(crate) struct DecodeLatAcc {
|
||||
pub(crate) count: u32,
|
||||
}
|
||||
|
||||
/// Host encode-stage latency accumulator — [`DecodeLatAcc`]'s mirror for the HOST side of the
|
||||
/// pipeline. The datagram task adds one sample per 0xCF `HostStages::encode_us` (host encoder
|
||||
/// submit → bitstream ready) and the pump drains a window mean into
|
||||
/// [`crate::abr::BitrateController::on_window`]'s encode signal. Host encode time was measured,
|
||||
/// shipped and drawn on the overlay, but never an ABR input — which is how a fat-LAN Automatic
|
||||
/// session drove the encoder past its compute knee with nothing to stop it (§ABR overdrive).
|
||||
/// Its own accumulator rather than the overlay's `host_timing` channel: that channel is a lossy
|
||||
/// `try_send` the embedder may never drain, and the controller must not depend on it.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct EncodeLatAcc {
|
||||
pub(crate) sum_us: u64,
|
||||
pub(crate) count: u32,
|
||||
}
|
||||
|
||||
/// The pre-decode video hand-off from the data-plane pump to the embedder. Unlike the side planes
|
||||
/// (self-contained samples that drop the newest on overflow), video AUs are reference-chained under the
|
||||
/// host's infinite GOP: dropping ANY frame mid-stream corrupts every dependent frame until the next
|
||||
|
||||
Reference in New Issue
Block a user