Skip to main content

smooth_runtime/client/
output.rs

1//! What the engine hands back: [`Output`], drained with
2//! [`super::SmoothClient::next_output`].
3
4use broadcast_common::impl_spec_display;
5use transmux::{Sample, TrackId, TrackSpec};
6
7use super::action::StreamId;
8use crate::error::SmoothError;
9
10/// One selectable video `QualityLevel`.
11#[derive(Debug, Clone, PartialEq, Eq)]
12#[non_exhaustive]
13pub struct QualityInfo {
14    /// `QualityLevel@Bitrate`, bits per second.
15    pub bitrate: u64,
16    /// `(MaxWidth, MaxHeight)`.
17    pub resolution: Option<(u32, u32)>,
18    /// The RFC 6381 codec string, when it can be derived.
19    pub codecs: Option<String>,
20}
21
22/// Why a manifest could not be used.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24#[non_exhaustive]
25pub enum ManifestFault {
26    /// The fetch failed (transport, timeout or HTTP status).
27    Fetch,
28    /// The body is not UTF-8.
29    Utf8,
30    /// The body is not a parseable Smooth manifest.
31    Parse,
32    /// A chunk timeline could not be enumerated.
33    Timeline,
34}
35
36impl ManifestFault {
37    /// A stable machine-readable label.
38    pub fn name(&self) -> &'static str {
39        match self {
40            Self::Fetch => "fetch",
41            Self::Utf8 => "utf8",
42            Self::Parse => "parse",
43            Self::Timeline => "timeline",
44        }
45    }
46}
47
48impl_spec_display!(ManifestFault);
49
50/// Something the engine gave up on and carried on without.
51#[derive(Debug, Clone, PartialEq, Eq)]
52#[non_exhaustive]
53pub enum Dropped {
54    /// A manifest fetch or parse failed and will be retried.
55    Manifest(ManifestFault),
56    /// A live fragment kept failing and was skipped.
57    Fragment {
58        /// The stream it belonged to.
59        stream: StreamId,
60        /// The final HTTP status, when HTTP failed it.
61        status: Option<u16>,
62    },
63    /// A fragment URL template did not resolve against the manifest URL.
64    FragmentUrl {
65        /// The stream it belonged to.
66        stream: StreamId,
67    },
68    /// A stream vanished from the refreshed manifest for too long and was dropped.
69    StreamLost {
70        /// The stream that was dropped.
71        stream: StreamId,
72    },
73}
74
75/// One thing the host should act on.
76#[derive(Debug, Clone)]
77#[non_exhaustive]
78pub enum Output {
79    /// The video `QualityLevel`s on offer and the index chosen.
80    Qualities {
81        /// One entry per `QualityLevel` of the first video stream.
82        qualities: Vec<QualityInfo>,
83        /// Index into `qualities`.
84        chosen: usize,
85    },
86    /// The first manifest fetch answered 404/410.
87    ManifestNotFound,
88    /// Every stream's first fragment resolved: the track set, one per stream, ids
89    /// `1..` in stream order.
90    Tracks(Vec<TrackSpec>),
91    /// A track's codec configuration changed because the host switched the video
92    /// `QualityLevel`: the complete replacement track set, same ids and order as
93    /// [`Output::Tracks`]. Emitted once, before the first sample of the new level;
94    /// [`Output::Tracks`] itself is announced only once.
95    TracksChanged(Vec<TrackSpec>),
96    /// One demuxed sample, timestamps in its track's timescale.
97    Sample {
98        /// The track carrying it.
99        track: TrackId,
100        /// The sample.
101        sample: Sample,
102    },
103    /// A gap in the timeline: samples were skipped or the live window moved past
104    /// the last fragment.
105    Discontinuity,
106    /// Carried on without something.
107    Dropped(Dropped),
108    /// A static presentation played to its end.
109    Ended,
110    /// The session is over.
111    Fatal(SmoothError),
112}