Skip to main content

dash_runtime/client/
mod.rs

1//! The sans-IO DASH client for static (VOD) presentations
2//! (`docs/dash-runtime/DESIGN.md` sections 1, 5 and 7).
3//!
4//! **Spec:** ISO/IEC 23009-1:2022 5.3.2 (Periods, continuity 5.3.2.4), 5.3.9
5//! (segment addressing, `sidx` 5.3.9.5.4), 5.6 (BaseURL), Annex A.9 (playback
6//! across Periods); ISO/IEC 14496-12:2026 8.8.4 / 8.14.3 (`moof`/`mdat`, `sidx`).
7//! Verbatim text: `private/specs-verified/dash/23009-1/`.
8//!
9//! [`DashClient`] is the `hls_runtime::client::HlsClient` analogue. The caller
10//! drains [`Action`]s, performs the I/O, feeds the answers back and drains
11//! [`Output`]s: one [`Manifest`](Output::Manifest) per Period, then the
12//! [`Tracks`](Output::Tracks) and ordered [`Samples`](Output::Samples) demuxed
13//! with `transmux::Fmp4Demux`. All selected AdaptationSets play on one
14//! timeline (design decision D7); Periods play back to back.
15//!
16//! What it does, and does not:
17//!
18//! * Static and dynamic MPDs. A dynamic one needs a UTC clock
19//!   ([`DashClient::set_wall_clock`], `UTCTiming` through
20//!   [`Action::FetchUtcTiming`], or the response `Date` in [`ResponseMeta`]),
21//!   gates every request on the segment's availability, refreshes the MPD
22//!   and reports [`Output::ClockSynced`]; see `next_wake` for timers.
23//! * fMP4/CMAF segments only; encrypted, MPEG-2 TS, WebM, subtitle and
24//!   trick-mode sets are reported as [`Output::TrackDropped`], never
25//!   misplayed.
26//! * Retry policy is the caller's. [`DashClient::on_failure`] classifies a
27//!   failure ([`FailureClass`]); the caller owns the backoff arithmetic and
28//!   calls [`DashClient::retry`]. A resource that fails
29//!   `DashConfig::max_segment_failures` times in a row ends the presentation
30//!   with [`Output::Fatal`] (the `broadcast-client` per-segment contract for a
31//!   VOD playlist).
32//! * Init segments are fetched concurrently per Representation and shared by
33//!   identical URL and range; `sidx` indexes are fetched before their
34//!   Representation's segments are planned; every request is a typed byte
35//!   range when the MPD says so.
36//! * With `DashConfig::cross_origin_urls = false` every URL the MPD makes the
37//!   client request must have the MPD's origin.
38//!
39//! No clock is read; the `now_us` arguments are the caller's monotonic clock.
40//!
41//! ```
42//! use dash_runtime::client::{Action, DashClient, DashConfig, PullLimits};
43//!
44//! let mut client = DashClient::new(dash_runtime::client::DashClientConfig::new("https://origin.example/vod/manifest.mpd").with_dash(DashConfig::default()).with_limits(PullLimits::default()));
45//! let Some(Action::FetchMpd { url, .. }) = client.poll(0) else { unreachable!() };
46//! assert_eq!(url, "https://origin.example/vod/manifest.mpd");
47//! // The MPD is requested once until the caller reports a failure and retries.
48//! assert!(client.poll(0).is_none());
49//! ```
50
51mod action;
52pub mod config;
53mod demux;
54mod engine;
55mod error;
56mod meta;
57mod output;
58mod utc_sampler;
59
60pub use action::{Action, MpdValidators, RepId, ResourceId, UtcId, UtcMethod};
61pub use config::{DashClockPolicy, DashConfig, DashConfigError, PullLimits, PullLimitsError};
62pub use engine::{DashClient, DashClientConfig, StateSize};
63pub use error::{Error, Failure, FailureClass, FailureKind, FatalKind, Rejection, Result};
64pub use meta::{ResponseMeta, UtcResponse};
65pub use output::{AudioRendition, DropCause, ManifestSelection, Notice, Output, VariantInfo};