1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Error, Debug)]
10pub enum Error {
11 #[error("Failed to fetch manifest: {0}")]
13 ManifestFetch(String),
14
15 #[error("Failed to parse manifest: {0}")]
16 ManifestParse(String),
17
18 #[error("Invalid manifest format: {0}")]
19 InvalidManifest(String),
20
21 #[error("No suitable rendition found")]
22 NoSuitableRendition,
23
24 #[error("Failed to fetch segment: {url}")]
26 SegmentFetch { url: String, source: reqwest::Error },
27
28 #[error("Segment timeout: {url}")]
29 SegmentTimeout { url: String },
30
31 #[error("Segment decryption failed")]
32 SegmentDecryption,
33
34 #[error("Buffer underrun")]
36 BufferUnderrun,
37
38 #[error("Buffer overflow")]
39 BufferOverflow,
40
41 #[error("Buffer seek failed: position {position}s not buffered")]
42 BufferSeekFailed { position: f64 },
43
44 #[error("DRM not supported: {system}")]
46 DrmNotSupported { system: String },
47
48 #[error("License acquisition failed: {0}")]
49 LicenseAcquisition(String),
50
51 #[error("License expired")]
52 LicenseExpired,
53
54 #[error("Content key not found")]
55 ContentKeyNotFound,
56
57 #[error("Playback stalled")]
59 PlaybackStalled,
60
61 #[error("Invalid playback state transition: {from} -> {to}")]
62 InvalidStateTransition { from: String, to: String },
63
64 #[error("Codec not supported: {codec}")]
65 CodecNotSupported { codec: String },
66
67 #[error("Network error: {0}")]
69 Network(#[from] reqwest::Error),
70
71 #[error("Connection timeout")]
72 ConnectionTimeout,
73
74 #[error("Invalid configuration: {0}")]
76 InvalidConfig(String),
77
78 #[error("Internal error: {0}")]
80 Internal(String),
81
82 #[error("IO error: {0}")]
83 Io(#[from] std::io::Error),
84}
85
86impl Error {
87 pub fn drm(msg: impl Into<String>) -> Self {
89 Error::LicenseAcquisition(msg.into())
90 }
91
92 pub fn is_recoverable(&self) -> bool {
94 matches!(
95 self,
96 Error::SegmentFetch { .. }
97 | Error::SegmentTimeout { .. }
98 | Error::BufferUnderrun
99 | Error::Network(_)
100 | Error::ConnectionTimeout
101 )
102 }
103
104 pub fn error_code(&self) -> &'static str {
106 match self {
107 Error::ManifestFetch(_) => "MANIFEST_FETCH",
108 Error::ManifestParse(_) => "MANIFEST_PARSE",
109 Error::InvalidManifest(_) => "INVALID_MANIFEST",
110 Error::NoSuitableRendition => "NO_RENDITION",
111 Error::SegmentFetch { .. } => "SEGMENT_FETCH",
112 Error::SegmentTimeout { .. } => "SEGMENT_TIMEOUT",
113 Error::SegmentDecryption => "SEGMENT_DECRYPT",
114 Error::BufferUnderrun => "BUFFER_UNDERRUN",
115 Error::BufferOverflow => "BUFFER_OVERFLOW",
116 Error::BufferSeekFailed { .. } => "BUFFER_SEEK",
117 Error::DrmNotSupported { .. } => "DRM_UNSUPPORTED",
118 Error::LicenseAcquisition(_) => "LICENSE_ACQUIRE",
119 Error::LicenseExpired => "LICENSE_EXPIRED",
120 Error::ContentKeyNotFound => "KEY_NOT_FOUND",
121 Error::PlaybackStalled => "PLAYBACK_STALLED",
122 Error::InvalidStateTransition { .. } => "INVALID_STATE",
123 Error::CodecNotSupported { .. } => "CODEC_UNSUPPORTED",
124 Error::Network(_) => "NETWORK",
125 Error::ConnectionTimeout => "TIMEOUT",
126 Error::InvalidConfig(_) => "INVALID_CONFIG",
127 Error::Internal(_) => "INTERNAL",
128 Error::Io(_) => "IO",
129 }
130 }
131}