-
Notifications
You must be signed in to change notification settings - Fork 3
kithara abr
Documentation reviewed from source revision 19ca073f2. This records the documented contract at that revision; it is not a new runtime validation. API and usage · All crates.
The controller consumes bandwidth and peer progress, records switch intent, and wakes the peer. It does not publish a variant change; publication belongs to the boundary owner described below. The decision implementation lives in the source linked above.
The configured decision policy handles manual selection, throughput, buffer urgency, escape, hysteresis, and the minimum switch interval. Rescue and manual decisions bypass that interval. A deferred decision records a deadline driven by the downloader and re-evaluates live evidence on expiry; it never caches a target or creates a separate ABR timer task.
AbrState separates intent from publication.
-
request_target(target, reason)records intent. Replace-pending, latest wins; a repeat request for the target already queued is a full no-op, ticket and reason included — the ticket names the exact transition a consumer has already built its incoming session and decoder against, so re-minting one would cancel that work on every tick and the switch could never finish. UnderManual(idx)a request for any other target is refused; the mode is read under the slot lock, pairing with the store-mode-then-clear-slot order inset_mode. The write happens regardless of lock state. -
AbrTicketidentifies one accepted request.pending_claim(current)reportsAbsent,Locked(claim), orReady(claim); a pending that already equalscurrentreportsAbsent. -
commit_pending(claim, now)publishes only when the slot still carries the same ticket and rebuilds the same decision, and never while locked.abort_pending(ticket)drops only the matching request; a stale ticket leaves a newer intent untouched. -
commit_pendingandapply_decisionare the only writers ofcurrent_variant. Production HLS commits through the publisher at a segment boundary (kithara-hlsstream/transition.rs);apply_decisionis the direct publish path. -
AbrPublisher(minted byAbrState::publisher()) is the publication capability the state's owner keeps. Consumers receiveAbrHandle, which observes and controls but cannot publish. -
lock()/unlock()are reentrant and gate publication only — the intent survives so it resumes on unlock.invalidate_pending()is the destructive counterpart, called on a semantic seek boundary: it drops throughput-driven intents (UpSwitch,DownSwitch,UrgentDownSwitch,EscapeStalled) and preservesManualOverride/Initial, which a position jump does not invalidate. -
retract_throughput_pending(current)runs from the tick'sStay { AlreadyOptimal }arm — the one verdict that re-affirmscurrenton live evidence. It drops a throughput-driven, non-rescue pending aimed elsewhere, so an urgent down-switch latched on the initial seed cannot outlive the estimate that justified it. -
set_modeclears the pending slot, except when a manual pin restates the target already queued. -
selected_variant_for_seek()returns the pending target when one exists, even while locked, so a seek replacement opens the variant the user is switching to.
mark_escape() flags the active variant as non-delivering; the HLS stall detector sets it when the reader is parked at a clean boundary on a segment whose in-flight fetch crossed the downloader soft timeout. The caller must follow with AbrHandle::reevaluate(): the flag is set under the HLS state lock and the tick re-locks that state through peer.progress(), so the tick must fire outside the lock. Publishing a new variant clears escape before storing it, so a concurrent tick that observes the new current_variant also observes the cleared flag and cannot immediately re-escape off a variant that has not had a chance to deliver.
Dual-track EWMA — fast (2 s half-life) and slow (10 s half-life); estimate = min(fast, slow), conservative by construction.
- Samples below 16 000 bytes are dropped as noise, fetch duration is clamped to ≥ 0.5 ms, and a zero fetch duration drops the sample in
record_bandwidthbefore it reaches the estimator. -
BandwidthSource::Cachenever feeds the EWMAs: it pins the fallback estimate to 100 Mbps so a cache hit is not mistaken for network throughput. - With no EWMA weight yet, the estimate falls back to the seed / cache value;
Noneonly when there is neither.
AbrSettings::initial_throughput_bps (default Some(2_000_000)) is applied to the estimator at controller construction so the first tick can pick a sensible variant before a real sample lands. ≈2 Mbps covers Wi-Fi and most 4G; constrained networks down-switch after the first real sample. It is a transient prior — real EWMA weight replaces it through the min(fast, slow) consensus. Set it to None for the cold-start path: decide() returns NoEstimate and the peer stays on its initial variant until samples accumulate.
AbrSettingsPatch is the second entry point: a configuration document types into it and apply writes past the builder, so a document can compose a setting the builder would have refused. One thing it cannot express — initial_throughput_bps and max_bandwidth_bps are already Option<u64>, so a document sets a value but cannot blank one: initial_throughput_bps: null reads as "leave it alone", not as the cold-start path above. The cold start stays a builder-only choice.
AbrSettings is the facade configuration for the controller: it carries both algorithm parameters and injected resources such as the optional parent CancelToken. It is #[non_exhaustive] and built with AbrSettings::builder()…build() (Default goes through the builder); initial_throughput_bps(Some(value)) sets the seed and initial_throughput_bps(None) explicitly disables it.
-
kithara-abrowns the public ABR event and value vocabulary:AbrEvent,AbrMode,AbrProgressSnapshot,AbrReason,BandwidthSource,BoundsError,VariantDuration,VariantIndex, andVariantInfo. - Variants live on the peer (
Abr::variants()), never inAbrState; they reach the decision throughAbrView.AbrStateowns only runtime control: current index, mode, lock count, escape flag, bandwidth cap, last-switch timestamp, pending slot. -
Abr::cancel()is mandatory and returns the protocol track/source token. The controller observes this token but never cancels it; HLS returns its stream token and File returns its source token. -
AbrHandle::set_modevalidatesManual(idx)against the peer's live variant list and returnsAbrError::VariantOutOfBounds;AbrState::set_modedoes not validate. -
AbrHandleis the consumer surface; dropping the last clone unregisters the peer. The track-scopedEventBuslives on the handle (with_bus), so peers stay free of event-bus plumbing. -
AbrControllerowns a child scope of the optional parent carried byAbrSettings. Each registration derives one controller-owned child and OR-combines it withAbr::cancel()throughCancelGroup; controller/parent cancellation stops every registration, protocol cancellation stops that track, and sibling registrations remain live. -
Downloader::runis the only async driver for ABR scheduling.AbrControllerstores coalesced tick requests, deadlines, and the downloader task's current waker; it never spawns a worker of its own. -
AbrController::register(peer)discovers protocol cancellation from the peer. Dropping the lastAbrHandlecancels only the controller-owned registration child, so unregister never cancels the protocol track or the controller scope. -
AbrHandle::notify_exact_commitpublishesAbrEvent::VariantAppliedafter a promotion and does nothing else. Its caller is the audio worker, which is not a runtime thread, so this path must not schedule async work. -
kithara-hlsreads the variant throughAbrHandle/Arc<AbrState>; no cloneableArc<AtomicUsize>handle is exposed — seeredundant_accessorsincrates/kithara-devtools/src/arch/checksfor the rationale.
Per peer: ThroughputSample at most every throughput_sample_min_interval (default 200 ms); BandwidthEstimate when bandwidth_emit_min_interval has elapsed or the relative change reaches bandwidth_emit_min_delta_ratio; BufferAhead on any Some/None transition, otherwise when both the interval and the absolute-delta thresholds are met.
Criterion microbenchmarks for the estimator/decision hot paths live in kithara-integration-tests:
cargo bench -p kithara-integration-tests --bench abr_estimator