1use alloc::vec::Vec;
10
11use crate::error::{Error, Result};
12use crate::time::{BreakDuration, SpliceTime};
13use crate::traits::CommandDef;
14use broadcast_common::{Parse, Serialize};
15
16pub const COMMAND_TYPE: u8 = 0x05;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22pub struct SpliceInsertComponent {
23 pub component_tag: u8,
25 pub splice_time: Option<SpliceTime>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize))]
33pub struct SpliceInsert {
34 pub splice_event_id: u32,
36 pub splice_event_cancel_indicator: bool,
39 pub out_of_network_indicator: bool,
41 pub program_splice_flag: bool,
44 pub splice_immediate_flag: bool,
47 pub event_id_compliance_flag: bool,
49 pub splice_time: Option<SpliceTime>,
52 pub components: Vec<SpliceInsertComponent>,
55 pub break_duration: Option<BreakDuration>,
57 pub unique_program_id: u16,
59 pub avail_num: u8,
61 pub avails_expected: u8,
63}
64
65impl Default for SpliceInsert {
66 fn default() -> Self {
67 Self {
68 splice_event_id: 0,
69 splice_event_cancel_indicator: false,
70 out_of_network_indicator: false,
71 program_splice_flag: true,
72 splice_immediate_flag: false,
73 event_id_compliance_flag: true,
74 splice_time: None,
75 components: Vec::new(),
76 break_duration: None,
77 unique_program_id: 0,
78 avail_num: 0,
79 avails_expected: 0,
80 }
81 }
82}
83
84impl<'a> Parse<'a> for SpliceInsert {
85 type Error = Error;
86 fn parse(bytes: &'a [u8]) -> Result<Self> {
87 let (hdr, _) = bytes
89 .split_first_chunk::<5>()
90 .ok_or(Error::BufferTooShort {
91 need: 5,
92 have: bytes.len(),
93 what: "splice_insert header",
94 })?;
95 let splice_event_id = u32::from_be_bytes([hdr[0], hdr[1], hdr[2], hdr[3]]);
96 let cancel = hdr[4] & 0x80 != 0;
97 let mut pos = 5;
98
99 let mut out = Self {
100 splice_event_id,
101 splice_event_cancel_indicator: cancel,
102 program_splice_flag: true,
103 event_id_compliance_flag: true,
104 ..Self::default()
105 };
106
107 if cancel {
108 return Ok(out);
109 }
110
111 if bytes.len() < pos + 1 {
112 return Err(Error::BufferTooShort {
113 need: pos + 1,
114 have: bytes.len(),
115 what: "splice_insert flags",
116 });
117 }
118 let flags = bytes[pos];
119 pos += 1;
120 out.out_of_network_indicator = flags & 0x80 != 0;
121 out.program_splice_flag = flags & 0x40 != 0;
122 let duration_flag = flags & 0x20 != 0;
123 out.splice_immediate_flag = flags & 0x10 != 0;
124 out.event_id_compliance_flag = flags & 0x08 != 0;
125
126 if out.program_splice_flag {
127 if !out.splice_immediate_flag {
128 let st = SpliceTime::parse(&bytes[pos..])?;
129 pos += st.serialized_len();
130 out.splice_time = Some(st);
131 }
132 } else {
133 if bytes.len() < pos + 1 {
135 return Err(Error::BufferTooShort {
136 need: pos + 1,
137 have: bytes.len(),
138 what: "splice_insert component_count",
139 });
140 }
141 let component_count = bytes[pos] as usize;
142 pos += 1;
143 for _ in 0..component_count {
144 if bytes.len() < pos + 1 {
145 return Err(Error::BufferTooShort {
146 need: pos + 1,
147 have: bytes.len(),
148 what: "splice_insert component_tag",
149 });
150 }
151 let component_tag = bytes[pos];
152 pos += 1;
153 let splice_time = if !out.splice_immediate_flag {
154 let st = SpliceTime::parse(&bytes[pos..])?;
155 pos += st.serialized_len();
156 Some(st)
157 } else {
158 None
159 };
160 out.components.push(SpliceInsertComponent {
161 component_tag,
162 splice_time,
163 });
164 }
165 }
166
167 if duration_flag {
168 let bd = BreakDuration::parse(&bytes[pos..])?;
169 pos += BreakDuration::LEN;
170 out.break_duration = Some(bd);
171 }
172
173 let (trailer, _) = bytes[pos..]
174 .split_first_chunk::<4>()
175 .ok_or(Error::BufferTooShort {
176 need: pos + 4,
177 have: bytes.len(),
178 what: "splice_insert trailer",
179 })?;
180 out.unique_program_id = u16::from_be_bytes([trailer[0], trailer[1]]);
181 out.avail_num = trailer[2];
182 out.avails_expected = trailer[3];
183 Ok(out)
184 }
185}
186
187impl Serialize for SpliceInsert {
188 type Error = Error;
189 fn serialized_len(&self) -> usize {
190 if self.splice_event_cancel_indicator {
191 return 5;
192 }
193 let mut len = 6; if self.program_splice_flag {
195 if !self.splice_immediate_flag {
196 len += self.splice_time.unwrap_or_default().serialized_len();
197 }
198 } else {
199 len += 1; for c in &self.components {
201 len += 1; if !self.splice_immediate_flag {
203 len += c.splice_time.unwrap_or_default().serialized_len();
204 }
205 }
206 }
207 if self.break_duration.is_some() {
208 len += BreakDuration::LEN;
209 }
210 len += 4; len
212 }
213
214 fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
215 let need = self.serialized_len();
216 if buf.len() < need {
217 return Err(Error::OutputBufferTooSmall {
218 need,
219 have: buf.len(),
220 });
221 }
222 buf[0..4].copy_from_slice(&self.splice_event_id.to_be_bytes());
223 buf[4] = (u8::from(self.splice_event_cancel_indicator) << 7) | 0x7F;
225 if self.splice_event_cancel_indicator {
226 return Ok(5);
227 }
228
229 let duration_flag = self.break_duration.is_some();
232 buf[5] = (u8::from(self.out_of_network_indicator) << 7)
233 | (u8::from(self.program_splice_flag) << 6)
234 | (u8::from(duration_flag) << 5)
235 | (u8::from(self.splice_immediate_flag) << 4)
236 | (u8::from(self.event_id_compliance_flag) << 3)
237 | 0x07;
238 let mut pos = 6;
239
240 if self.program_splice_flag {
241 if !self.splice_immediate_flag {
242 let st = self.splice_time.unwrap_or_default();
243 pos += st.serialize_into(&mut buf[pos..])?;
244 }
245 } else {
246 buf[pos] = self.components.len() as u8;
247 pos += 1;
248 for c in &self.components {
249 buf[pos] = c.component_tag;
250 pos += 1;
251 if !self.splice_immediate_flag {
252 let st = c.splice_time.unwrap_or_default();
253 pos += st.serialize_into(&mut buf[pos..])?;
254 }
255 }
256 }
257
258 if let Some(bd) = self.break_duration {
259 pos += bd.serialize_into(&mut buf[pos..])?;
260 }
261
262 buf[pos..pos + 2].copy_from_slice(&self.unique_program_id.to_be_bytes());
263 buf[pos + 2] = self.avail_num;
264 buf[pos + 3] = self.avails_expected;
265 Ok(need)
266 }
267}
268
269impl<'a> CommandDef<'a> for SpliceInsert {
270 const COMMAND_TYPE: u8 = COMMAND_TYPE;
271 const NAME: &'static str = "SPLICE_INSERT";
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 fn rt(cmd: &SpliceInsert) {
279 let bytes = cmd.to_bytes();
280 assert_eq!(bytes.len(), cmd.serialized_len());
281 let back = SpliceInsert::parse(&bytes).unwrap();
282 assert_eq!(*cmd, back);
283 assert_eq!(back.to_bytes(), bytes);
284 }
285
286 #[test]
287 fn round_trip_cancel() {
288 rt(&SpliceInsert {
289 splice_event_id: 0xDEADBEEF,
290 splice_event_cancel_indicator: true,
291 ..Default::default()
292 });
293 }
294
295 #[test]
296 fn round_trip_program_with_time_and_duration() {
297 rt(&SpliceInsert {
298 splice_event_id: 0x4800_0001,
299 out_of_network_indicator: true,
300 program_splice_flag: true,
301 splice_immediate_flag: false,
302 event_id_compliance_flag: false,
303 splice_time: Some(SpliceTime::with_pts(0x0_0123_4567)),
304 break_duration: Some(BreakDuration {
305 auto_return: true,
306 duration: 90_000 * 30,
307 }),
308 unique_program_id: 0x1234,
309 avail_num: 1,
310 avails_expected: 4,
311 ..Default::default()
312 });
313 }
314
315 #[test]
316 fn round_trip_program_immediate() {
317 rt(&SpliceInsert {
318 splice_event_id: 0x6000_0009,
319 program_splice_flag: true,
320 splice_immediate_flag: true,
321 splice_time: None,
322 unique_program_id: 7,
323 ..Default::default()
324 });
325 }
326
327 #[test]
328 fn round_trip_component_mode() {
329 rt(&SpliceInsert {
330 splice_event_id: 0xC000_0002,
331 program_splice_flag: false,
332 splice_immediate_flag: false,
333 components: vec![
334 SpliceInsertComponent {
335 component_tag: 1,
336 splice_time: Some(SpliceTime::with_pts(0x1000)),
337 },
338 SpliceInsertComponent {
339 component_tag: 2,
340 splice_time: Some(SpliceTime::default()),
341 },
342 ],
343 unique_program_id: 9,
344 ..Default::default()
345 });
346 }
347}