1use alloc::vec::Vec;
9
10use crate::error::{Error, Result};
11use crate::time::BreakDuration;
12use crate::traits::CommandDef;
13use broadcast_common::{Parse, Serialize};
14
15pub const COMMAND_TYPE: u8 = 0x04;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize))]
21pub struct SpliceScheduleComponent {
22 pub component_tag: u8,
24 pub utc_splice_time: u32,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
30#[cfg_attr(feature = "serde", derive(serde::Serialize))]
31pub struct SpliceScheduleEvent {
32 pub splice_event_id: u32,
34 pub splice_event_cancel_indicator: bool,
36 pub event_id_compliance_flag: bool,
38 pub out_of_network_indicator: bool,
40 pub program_splice_flag: bool,
42 pub utc_splice_time: Option<u32>,
44 pub components: Vec<SpliceScheduleComponent>,
47 pub break_duration: Option<BreakDuration>,
49 pub unique_program_id: u16,
51 pub avail_num: u8,
53 pub avails_expected: u8,
55}
56
57impl Default for SpliceScheduleEvent {
58 fn default() -> Self {
59 Self {
60 splice_event_id: 0,
61 splice_event_cancel_indicator: false,
62 event_id_compliance_flag: true,
63 out_of_network_indicator: false,
64 program_splice_flag: true,
65 utc_splice_time: None,
66 components: Vec::new(),
67 break_duration: None,
68 unique_program_id: 0,
69 avail_num: 0,
70 avails_expected: 0,
71 }
72 }
73}
74
75impl SpliceScheduleEvent {
76 fn serialized_len(&self) -> usize {
77 let mut len = 5;
79 if self.splice_event_cancel_indicator {
80 return len;
81 }
82 len += 1; if self.program_splice_flag {
84 len += 4; } else {
86 len += 1; len += self.components.len() * 5; }
89 if self.break_duration.is_some() {
90 len += BreakDuration::LEN;
91 }
92 len += 4; len
94 }
95
96 fn parse_at(bytes: &[u8], pos: &mut usize) -> Result<Self> {
97 let (hdr, _) = bytes[*pos..]
98 .split_first_chunk::<5>()
99 .ok_or(Error::BufferTooShort {
100 need: *pos + 5,
101 have: bytes.len(),
102 what: "splice_schedule event header",
103 })?;
104 let splice_event_id = u32::from_be_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]);
105 let b = hdr[4];
106 *pos += 5;
107 let cancel = b & 0x80 != 0;
108 let compliance = b & 0x40 != 0;
109
110 let mut ev = Self {
111 splice_event_id,
112 splice_event_cancel_indicator: cancel,
113 event_id_compliance_flag: compliance,
114 ..Self::default()
115 };
116 if cancel {
117 return Ok(ev);
118 }
119
120 if bytes.len() < *pos + 1 {
121 return Err(Error::BufferTooShort {
122 need: *pos + 1,
123 have: bytes.len(),
124 what: "splice_schedule event flags",
125 });
126 }
127 let flags = bytes[*pos];
128 *pos += 1;
129 ev.out_of_network_indicator = flags & 0x80 != 0;
130 ev.program_splice_flag = flags & 0x40 != 0;
131 let duration_flag = flags & 0x20 != 0;
132
133 if ev.program_splice_flag {
134 let (t, _) = bytes[*pos..]
135 .split_first_chunk::<4>()
136 .ok_or(Error::BufferTooShort {
137 need: *pos + 4,
138 have: bytes.len(),
139 what: "splice_schedule utc_splice_time",
140 })?;
141 ev.utc_splice_time = Some(u32::from_be_bytes(*t));
142 *pos += 4;
143 } else {
144 if bytes.len() < *pos + 1 {
145 return Err(Error::BufferTooShort {
146 need: *pos + 1,
147 have: bytes.len(),
148 what: "splice_schedule component_count",
149 });
150 }
151 let count = bytes[*pos] as usize;
152 *pos += 1;
153 for _ in 0..count {
154 let (comp, _) =
155 bytes[*pos..]
156 .split_first_chunk::<5>()
157 .ok_or(Error::BufferTooShort {
158 need: *pos + 5,
159 have: bytes.len(),
160 what: "splice_schedule component",
161 })?;
162 let component_tag = comp[0];
163 let utc_splice_time = u32::from_be_bytes([comp[1], comp[2], comp[3], comp[4]]);
164 *pos += 5;
165 ev.components.push(SpliceScheduleComponent {
166 component_tag,
167 utc_splice_time,
168 });
169 }
170 }
171
172 if duration_flag {
173 ev.break_duration = Some(BreakDuration::parse(&bytes[*pos..])?);
174 *pos += BreakDuration::LEN;
175 }
176
177 let (trailer, _) = bytes[*pos..]
178 .split_first_chunk::<4>()
179 .ok_or(Error::BufferTooShort {
180 need: *pos + 4,
181 have: bytes.len(),
182 what: "splice_schedule event trailer",
183 })?;
184 ev.unique_program_id = u16::from_be_bytes([trailer[0], trailer[1]]);
185 ev.avail_num = trailer[2];
186 ev.avails_expected = trailer[3];
187 *pos += 4;
188 Ok(ev)
189 }
190
191 fn serialize_at(&self, buf: &mut [u8], pos: &mut usize) -> Result<()> {
192 buf[*pos..*pos + 4].copy_from_slice(&self.splice_event_id.to_be_bytes());
193 buf[*pos + 4] = (u8::from(self.splice_event_cancel_indicator) << 7)
195 | (u8::from(self.event_id_compliance_flag) << 6)
196 | 0x3F;
197 *pos += 5;
198 if self.splice_event_cancel_indicator {
199 return Ok(());
200 }
201
202 let duration_flag = self.break_duration.is_some();
203 buf[*pos] = (u8::from(self.out_of_network_indicator) << 7)
205 | (u8::from(self.program_splice_flag) << 6)
206 | (u8::from(duration_flag) << 5)
207 | 0x1F;
208 *pos += 1;
209
210 if self.program_splice_flag {
211 buf[*pos..*pos + 4].copy_from_slice(&self.utc_splice_time.unwrap_or(0).to_be_bytes());
212 *pos += 4;
213 } else {
214 buf[*pos] = self.components.len() as u8;
215 *pos += 1;
216 for c in &self.components {
217 buf[*pos] = c.component_tag;
218 buf[*pos + 1..*pos + 5].copy_from_slice(&c.utc_splice_time.to_be_bytes());
219 *pos += 5;
220 }
221 }
222
223 if let Some(bd) = self.break_duration {
224 *pos += bd.serialize_into(&mut buf[*pos..])?;
225 }
226
227 buf[*pos..*pos + 2].copy_from_slice(&self.unique_program_id.to_be_bytes());
228 buf[*pos + 2] = self.avail_num;
229 buf[*pos + 3] = self.avails_expected;
230 *pos += 4;
231 Ok(())
232 }
233}
234
235#[derive(Debug, Clone, PartialEq, Eq, Default)]
237#[cfg_attr(feature = "serde", derive(serde::Serialize))]
238pub struct SpliceSchedule {
239 pub events: Vec<SpliceScheduleEvent>,
241}
242
243impl<'a> Parse<'a> for SpliceSchedule {
244 type Error = Error;
245 fn parse(bytes: &'a [u8]) -> Result<Self> {
246 if bytes.is_empty() {
247 return Err(Error::BufferTooShort {
248 need: 1,
249 have: 0,
250 what: "splice_schedule splice_count",
251 });
252 }
253 let count = bytes[0] as usize;
254 let mut pos = 1;
255 let mut events = Vec::with_capacity(count);
256 for _ in 0..count {
257 events.push(SpliceScheduleEvent::parse_at(bytes, &mut pos)?);
258 }
259 Ok(Self { events })
260 }
261}
262
263impl Serialize for SpliceSchedule {
264 type Error = Error;
265 fn serialized_len(&self) -> usize {
266 1 + self
267 .events
268 .iter()
269 .map(SpliceScheduleEvent::serialized_len)
270 .sum::<usize>()
271 }
272 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
273 let need = self.serialized_len();
274 if buf.len() < need {
275 return Err(Error::OutputBufferTooSmall {
276 need,
277 have: buf.len(),
278 });
279 }
280 buf[0] = self.events.len() as u8;
281 let mut pos = 1;
282 for ev in &self.events {
283 ev.serialize_at(buf, &mut pos)?;
284 }
285 Ok(need)
286 }
287}
288
289impl<'a> CommandDef<'a> for SpliceSchedule {
290 const COMMAND_TYPE: u8 = COMMAND_TYPE;
291 const NAME: &'static str = "SPLICE_SCHEDULE";
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 fn rt(cmd: &SpliceSchedule) {
299 let bytes = cmd.to_bytes();
300 assert_eq!(bytes.len(), cmd.serialized_len());
301 let back = SpliceSchedule::parse(&bytes).unwrap();
302 assert_eq!(*cmd, back);
303 assert_eq!(back.to_bytes(), bytes);
304 }
305
306 #[test]
307 fn round_trip_empty_schedule() {
308 rt(&SpliceSchedule::default());
309 }
310
311 #[test]
312 fn round_trip_program_events() {
313 rt(&SpliceSchedule {
314 events: vec![
315 SpliceScheduleEvent {
316 splice_event_id: 1,
317 out_of_network_indicator: true,
318 utc_splice_time: Some(0x1234_5678),
319 break_duration: Some(BreakDuration {
320 auto_return: false,
321 duration: 100,
322 }),
323 unique_program_id: 5,
324 avail_num: 1,
325 avails_expected: 2,
326 ..Default::default()
327 },
328 SpliceScheduleEvent {
329 splice_event_id: 2,
330 splice_event_cancel_indicator: true,
331 ..Default::default()
332 },
333 ],
334 });
335 }
336
337 #[test]
338 fn round_trip_component_event() {
339 rt(&SpliceSchedule {
340 events: vec![SpliceScheduleEvent {
341 splice_event_id: 3,
342 program_splice_flag: false,
343 components: vec![
344 SpliceScheduleComponent {
345 component_tag: 1,
346 utc_splice_time: 0xAABBCCDD,
347 },
348 SpliceScheduleComponent {
349 component_tag: 2,
350 utc_splice_time: 0x11223344,
351 },
352 ],
353 unique_program_id: 9,
354 ..Default::default()
355 }],
356 });
357 }
358}