Skip to main content

hls_runtime/client/
mod.rs

1//! LL-HLS playback client engine — a sans-IO Low-Latency HLS (RFC 8216bis)
2//! client (issue #717, slices 2-4; the `client` module of `hls-runtime` — see
3//! `docs/superpowers/specs/2026-07-18-multimux-hub-design.md`).
4//!
5//! [`HlsClient`] is a driveable, caller-driven state machine — the same
6//! sans-IO shape as `srt-runtime` (issue #565): the core never opens a socket
7//! or reads a clock. The caller drains [`Action`]s (what to fetch, and how),
8//! performs the IO itself, and feeds the response back in via
9//! [`HlsClient::on_playlist`] / [`HlsClient::on_resource`] /
10//! [`HlsClient::on_error`]; decoded [`Output`]s (the init segment, then
11//! ordered access units) drain out via [`HlsClient::next_output`].
12//!
13//! # Reuse, not re-description
14//!
15//! This module defines **no playlist model of its own**. Parsing is
16//! [`broadcast_hls::MediaPlaylist::parse`] (issue #717 slice 1 — the
17//! symmetric inverse of the LL-HLS origin's own `to_m3u8()` renderer, so
18//! origin and client share one wire model); demuxing a fetched CMAF part or
19//! segment into access units is [`transmux::Fmp4Demux`]. `client` holds only
20//! the client **engine**: the reload scheduler, the fetch pipeline
21//! (prefetch/byte-range/dedup), and the output ordering — see
22//! [`HlsClient`]'s docs for the full behaviour.
23//!
24//! # Zero IO in the core
25//!
26//! No `tokio`/`reqwest`/socket dependency in [`HlsClient`] itself, ever —
27//! it is driveable by hand (see the crate's `hls-runtime/tests/it/origin_loop.rs` for a
28//! complete in-process example against a real
29//! `transmux::ll_hls::LlHlsSegmenter` origin) with zero IO dependencies at
30//! all (verified by the `--no-default-features` gate).
31//!
32//! # Example
33//!
34//! ```
35//! use hls_runtime::client::{Action, HlsClient};
36//!
37//! let mut client = HlsClient::new(hls_runtime::client::HlsClientConfig::new("http://origin/live/stream.m3u8"));
38//! // The caller performs this GET; here we just inspect the first action.
39//! match client.poll() {
40//!     Some(Action::FetchPlaylist { url, blocking, .. }) => {
41//!         assert_eq!(url, "http://origin/live/stream.m3u8");
42//!         assert!(blocking.is_none()); // nothing fetched yet, so no LL info.
43//!     }
44//!     other => panic!("unexpected first action: {other:?}"),
45//! }
46//! ```
47
48mod action;
49mod engine;
50mod error;
51mod output;
52mod url;
53
54pub use action::{Action, BlockingReload, KeyId, ResourceId};
55pub use engine::{HlsClient, HlsClientConfig, choose_variant};
56pub use error::{Error, Result};
57pub use output::{MasterSelection, Output, RenditionInfo, VariantInfo, VariantPolicy};