1use crate::{
34 container::{MuxHint, MuxTiming, Muxer},
35 packet::Packet,
36 session::{ErasedError, ProtocolViolation, SessionError, UnsupportedMedia},
37 track::TrackInfo,
38};
39use alloc::{boxed::Box, vec::Vec};
40
41use std::{
42 error::Error,
43 fmt,
44 io::{self, Write},
45};
46use zencodec::operation::DestinationFacts;
47
48type Cause = Box<dyn Error + Send + Sync>;
49
50pub use zencodec_io::destination::{Destination, Forward, SeekBack};
52
53#[derive(Clone, Copy, Debug)]
54#[non_exhaustive]
55pub enum Stage {
57 Prepare,
59 Packet,
61 Drain,
63 Finish,
65 Patch,
67}
68
69#[derive(Debug)]
70#[non_exhaustive]
71pub struct Failure {
74 pub stage: Stage,
76 pub emitted: u64,
78 pub cause: Cause,
80}
81impl fmt::Display for Failure {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 write!(
84 f,
85 "mux {:?} failed after {} appended bytes",
86 self.stage, self.emitted
87 )
88 }
89}
90impl Error for Failure {
91 fn source(&self) -> Option<&(dyn Error + 'static)> {
92 Some(&*self.cause)
93 }
94}
95
96#[derive(Default, Debug)]
97#[non_exhaustive]
98pub struct Stats {
100 pub emitted: u64,
102 pub patches: usize,
104 pub patch_bytes: usize,
106 pub max_pending: usize,
108}
109
110pub struct Output<M, D> {
113 mux: Option<M>,
114 destination: D,
115 tracks: Vec<TrackInfo>,
116 timing: MuxTiming,
117 exact_timing: bool,
118 stats: Stats,
119}
120
121pub struct PreparedOutput<M, D>(Output<M, D>);
124impl<M: Muxer, D: Destination> PreparedOutput<M, D> {
125 pub fn new(
127 mux: M,
128 destination: D,
129 tracks: &[TrackInfo],
130 pulse: Option<&dyn zencodec::Pulse>,
131 ) -> Result<Self, Failure> {
132 let pulse = pulse.unwrap_or(&zencodec::NoPulse);
133 Output::prepare_unpublished(mux, destination, tracks, pulse, true, M::begin_exact_timing)
134 .map(Self)
135 }
136 pub const fn timing(&self) -> MuxTiming {
139 self.0.timing
140 }
141 pub fn facts(&self) -> DestinationFacts {
144 self.0.facts()
145 }
146 pub(crate) fn validate_packet(&self, packet: &Packet) -> Result<(), Cause> {
147 self.0.validate_packet(packet)
148 }
149 pub fn publish(self, pulse: Option<&dyn zencodec::Pulse>) -> Result<Output<M, D>, Failure> {
151 let pulse = pulse.unwrap_or(&zencodec::NoPulse);
152 let mut output = self.0;
153 let mut mux = output.mux.take().expect("prepared muxer is retained");
154 output
155 .drain(&mut mux, pulse)
156 .map_err(|cause| output.failure(Stage::Drain, cause))?;
157 output.mux = Some(mux);
158 Ok(output)
159 }
160}
161
162fn stopped(pulse: &dyn zencodec::Pulse) -> Result<(), Cause> {
163 pulse
164 .check()
165 .map_err(|reason| Box::new(SessionError::<ErasedError>::Cancelled(reason)) as Cause)
166}
167fn protocol(kind: ProtocolViolation) -> Cause {
168 Box::new(SessionError::<ErasedError>::Protocol(kind))
169}
170
171fn write_all(
172 writer: &mut impl Write,
173 mut bytes: &[u8],
174 count: &mut u64,
175 pulse: &dyn zencodec::Pulse,
176) -> Result<(), Cause> {
177 while !bytes.is_empty() {
178 stopped(pulse)?;
179 match writer.write(bytes) {
180 Ok(0) => return Err(io::Error::from(io::ErrorKind::WriteZero).into()),
181 Ok(n) if n <= bytes.len() => {
182 *count = count
183 .checked_add(n as u64)
184 .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
185 bytes = &bytes[n..];
186 }
187 Ok(_) => return Err(io::Error::from(io::ErrorKind::InvalidData).into()),
188 Err(e) if e.kind() == io::ErrorKind::Interrupted => {}
189 Err(e) => return Err(e.into()),
190 }
191 }
192 stopped(pulse)
193}
194
195impl<M: Muxer, D: Destination> Output<M, D> {
196 pub fn with_container_timing(
199 mux: M,
200 destination: D,
201 tracks: &[TrackInfo],
202 pulse: Option<&dyn zencodec::Pulse>,
203 ) -> Result<Self, Failure> {
204 Self::prepare(mux, destination, tracks, pulse, false, M::begin)
205 }
206
207 pub fn new(
209 mux: M,
210 destination: D,
211 tracks: &[TrackInfo],
212 pulse: Option<&dyn zencodec::Pulse>,
213 ) -> Result<Self, Failure> {
214 Self::prepare(mux, destination, tracks, pulse, true, M::begin_exact_timing)
215 }
216
217 fn prepare(
218 mux: M,
219 destination: D,
220 tracks: &[TrackInfo],
221 pulse: Option<&dyn zencodec::Pulse>,
222 exact_timing: bool,
223 begin: impl FnOnce(&mut M, &[TrackInfo], MuxHint) -> Result<MuxTiming, SessionError<M::Error>>,
224 ) -> Result<Self, Failure> {
225 PreparedOutput(Self::prepare_unpublished(
226 mux,
227 destination,
228 tracks,
229 pulse.unwrap_or(&zencodec::NoPulse),
230 exact_timing,
231 begin,
232 )?)
233 .publish(pulse)
234 }
235
236 fn prepare_unpublished(
237 mut mux: M,
238 destination: D,
239 tracks: &[TrackInfo],
240 pulse: &dyn zencodec::Pulse,
241 exact_timing: bool,
242 begin: impl FnOnce(&mut M, &[TrackInfo], MuxHint) -> Result<MuxTiming, SessionError<M::Error>>,
243 ) -> Result<Self, Failure> {
244 let prepare = || -> Result<_, Cause> {
245 stopped(pulse)?;
246 let hint = if destination.can_patch() {
247 MuxHint::default()
248 } else {
249 MuxHint::forward_only()
250 };
251 let timing = begin(&mut mux, tracks, hint)?;
252 if timing.patches_at_finish() && !destination.can_patch() {
253 return Err(Box::new(SessionError::<ErasedError>::Unsupported(
254 UnsupportedMedia::ForwardOnlyLayout,
255 )));
256 }
257 stopped(pulse)?;
258 Ok(timing)
259 };
260 let timing = prepare().map_err(|cause| Failure {
261 stage: Stage::Prepare,
262 emitted: 0,
263 cause,
264 })?;
265 Ok(Self {
266 mux: Some(mux),
267 destination,
268 tracks: tracks.to_vec(),
269 timing,
270 exact_timing,
271 stats: Stats::default(),
272 })
273 }
274 pub fn facts(&self) -> DestinationFacts {
277 DestinationFacts::new(
278 self.destination.can_patch(),
279 self.timing.streams(),
280 self.timing.patches_at_finish(),
281 self.exact_timing,
282 )
283 }
284 fn validate_packet(&self, packet: &Packet) -> Result<(), Cause> {
285 let track = self
286 .tracks
287 .iter()
288 .find(|track| track.index() == packet.track())
289 .ok_or_else(|| protocol(ProtocolViolation::NotConfigured))?;
290 if packet.config_epoch() != track.config_epoch() {
291 return Err(protocol(ProtocolViolation::EpochMismatch));
292 }
293 for timestamp in [packet.pts(), packet.dts()].into_iter().flatten() {
294 if timestamp.base() != track.time_base() {
295 return Err(protocol(ProtocolViolation::ClockMismatch));
296 }
297 }
298 Ok(())
299 }
300 fn failure(&self, stage: Stage, cause: Cause) -> Failure {
301 Failure {
302 stage,
303 emitted: self.stats.emitted,
304 cause,
305 }
306 }
307 fn drain(&mut self, mux: &mut M, pulse: &dyn zencodec::Pulse) -> Result<(), Cause> {
308 let bytes = mux.pending_output();
309 self.stats.max_pending = self.stats.max_pending.max(bytes.len());
310 write_all(&mut self.destination, bytes, &mut self.stats.emitted, pulse)?;
311 mux.consume_output(bytes.len());
312 Ok(())
313 }
314 pub const fn stats(&self) -> &Stats {
316 &self.stats
317 }
318 pub fn is_failed(&self) -> bool {
320 self.mux.is_none()
321 }
322 pub fn send(
324 &mut self,
325 packet: Packet,
326 pulse: Option<&dyn zencodec::Pulse>,
327 ) -> Result<(), Failure> {
328 let local_pulse = pulse.unwrap_or(&zencodec::NoPulse);
329 let mut mux = self.mux.take().ok_or_else(|| {
330 self.failure(
331 Stage::Packet,
332 Box::new(SessionError::<ErasedError>::Finished),
333 )
334 })?;
335 let work = || -> Result<(), Cause> {
336 stopped(local_pulse)?;
337 self.validate_packet(&packet)?;
338 mux.write_packet(packet, pulse)?;
339 self.drain(&mut mux, local_pulse)?;
340 Ok(())
341 };
342 work().map_err(|cause| self.failure(Stage::Packet, cause))?;
343 self.mux = Some(mux);
344 Ok(())
345 }
346 pub fn finish(mut self, pulse: Option<&dyn zencodec::Pulse>) -> Result<Stats, Failure> {
349 let local_pulse = pulse.unwrap_or(&zencodec::NoPulse);
350 let mux = self.mux.take().ok_or_else(|| {
351 self.failure(
352 Stage::Finish,
353 Box::new(SessionError::<ErasedError>::Finished),
354 )
355 })?;
356 stopped(local_pulse).map_err(|cause| self.failure(Stage::Finish, cause))?;
357 let finish = mux
358 .finish(pulse)
359 .map_err(|e| self.failure(Stage::Finish, Box::new(e)))?;
360 let total = finish
361 .validate(self.stats.emitted)
362 .map_err(|e| self.failure(Stage::Finish, Box::new(e)))?;
363 if !finish.patches.is_empty()
364 && (!self.destination.can_patch() || !self.timing.patches_at_finish())
365 {
366 return Err(self.failure(
367 Stage::Finish,
368 Box::new(SessionError::<ErasedError>::Unsupported(
369 UnsupportedMedia::ForwardOnlyLayout,
370 )),
371 ));
372 }
373 self.stats.max_pending = self.stats.max_pending.max(finish.tail.len());
374 write_all(
375 &mut self.destination,
376 &finish.tail,
377 &mut self.stats.emitted,
378 local_pulse,
379 )
380 .map_err(|cause| self.failure(Stage::Finish, cause))?;
381 self.stats.patches = finish.patches.len();
382 for patch in finish.patches {
383 self.destination
384 .position(patch.offset)
385 .map_err(|e| self.failure(Stage::Patch, Box::new(e)))?;
386 let mut written = 0;
387 write_all(
388 &mut self.destination,
389 &patch.bytes,
390 &mut written,
391 local_pulse,
392 )
393 .map_err(|cause| self.failure(Stage::Patch, cause))?;
394 self.stats.patch_bytes += patch.bytes.len();
395 }
396 if self.stats.patches > 0 {
397 self.destination
398 .position(total)
399 .map_err(|e| self.failure(Stage::Patch, Box::new(e)))?;
400 }
401 self.destination
402 .flush()
403 .map_err(|e| self.failure(Stage::Finish, Box::new(e)))?;
404 stopped(local_pulse).map_err(|cause| self.failure(Stage::Finish, cause))?;
405 Ok(self.stats)
406 }
407}