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}