Skip to main content

dvb_si/descriptors/
announcement_support.rs

1//! Announcement Support Descriptor — ETSI EN 300 468 §6.2.3 (tag 0x6E, Table 17, PDF p. 56).
2//!
3//! Carried inside the SDT. Signals which announcement types (emergency,
4//! traffic, news, weather, …) a service supports and where each is carried.
5//! Body layout (Table 17):
6//!
7//! ```text
8//! announcement_support_indicator 16
9//! for (i=0;i<N;i++) {
10//!   announcement_type   4
11//!   reserved_future_use 1
12//!   reference_type      3
13//!   if (reference_type == 0x01 || 0x02 || 0x03) {
14//!     original_network_id 16
15//!     transport_stream_id 16
16//!     service_id          16
17//!     component_tag        8
18//!   }
19//! }
20//! ```
21//!
22//! The conditional reference fields (onid/tsid/sid/component_tag) are present
23//! only for reference_type 1, 2, 3 (verified against PDF p. 56). They are
24//! modelled as an `Option<AnnouncementReference>`.
25
26use super::descriptor_body;
27use crate::error::{Error, Result};
28use dvb_common::{Parse, Serialize};
29
30/// Descriptor tag for announcement_support_descriptor.
31pub const TAG: u8 = 0x6E;
32/// Length of the header (tag byte + length byte).
33pub const HEADER_LEN: usize = 2;
34/// Length of the announcement_support_indicator field.
35pub const INDICATOR_LEN: usize = 2;
36/// Length of the announcement_type/reserved/reference_type byte.
37pub const TYPE_BYTE_LEN: usize = 1;
38/// Length of the conditional reference block: onid(2)+tsid(2)+sid(2)+component_tag(1).
39pub const REFERENCE_LEN: usize = 7;
40
41const ANNOUNCEMENT_TYPE_MASK: u8 = 0xF0;
42const ANNOUNCEMENT_TYPE_SHIFT: u8 = 4;
43const RESERVED_BIT_MASK: u8 = 0x08;
44const REFERENCE_TYPE_MASK: u8 = 0x07;
45/// Max value of the 4-bit announcement_type field.
46pub const ANNOUNCEMENT_TYPE_MAX: u8 = 0x0F;
47/// Max value of the 3-bit reference_type field.
48pub const REFERENCE_TYPE_MAX: u8 = 0x07;
49
50/// Conditional reference block, present for reference_type 1, 2, 3.
51#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[cfg_attr(feature = "serde", derive(serde::Serialize))]
53pub struct AnnouncementReference {
54    /// original_network_id of the carrying TS.
55    pub original_network_id: u16,
56    /// transport_stream_id of the carrying TS.
57    pub transport_stream_id: u16,
58    /// service_id carrying the announcement.
59    pub service_id: u16,
60    /// component_tag identifying the elementary stream.
61    pub component_tag: u8,
62}
63
64/// One announcement entry.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize))]
67pub struct AnnouncementEntry {
68    /// 4-bit announcement_type (Table 19).
69    pub announcement_type: u8,
70    /// 3-bit reference_type (Table 20).
71    pub reference_type: u8,
72    /// Reference block, present iff reference_type ∈ {1,2,3}.
73    pub reference: Option<AnnouncementReference>,
74}
75
76/// Announcement Support Descriptor.
77#[derive(Debug, Clone, PartialEq, Eq)]
78#[cfg_attr(feature = "serde", derive(serde::Serialize))]
79pub struct AnnouncementSupportDescriptor {
80    /// 16-bit announcement_support_indicator flag field (TS 101 154 C.4.3).
81    pub announcement_support_indicator: u16,
82    /// Announcement entries in wire order.
83    pub entries: Vec<AnnouncementEntry>,
84}
85
86#[inline]
87fn reference_present(reference_type: u8) -> bool {
88    matches!(reference_type, 0x01..=0x03)
89}
90
91impl<'a> Parse<'a> for AnnouncementSupportDescriptor {
92    type Error = crate::error::Error;
93    fn parse(bytes: &'a [u8]) -> Result<Self> {
94        let body = descriptor_body(
95            bytes,
96            TAG,
97            "AnnouncementSupportDescriptor",
98            "unexpected tag for announcement_support_descriptor",
99        )?;
100        if body.len() < INDICATOR_LEN {
101            return Err(Error::InvalidDescriptor {
102                tag: TAG,
103                reason: "body too short (need announcement_support_indicator)",
104            });
105        }
106        let announcement_support_indicator = u16::from_be_bytes([body[0], body[1]]);
107        let mut entries = Vec::new();
108        let mut pos = INDICATOR_LEN;
109        while pos < body.len() {
110            let flags = body[pos];
111            pos += TYPE_BYTE_LEN;
112            // reserved_future_use bit ignored on parse (§5.1).
113            let announcement_type = (flags & ANNOUNCEMENT_TYPE_MASK) >> ANNOUNCEMENT_TYPE_SHIFT;
114            let reference_type = flags & REFERENCE_TYPE_MASK;
115            let reference = if reference_present(reference_type) {
116                if pos + REFERENCE_LEN > body.len() {
117                    return Err(Error::InvalidDescriptor {
118                        tag: TAG,
119                        reason: "announcement reference block truncated",
120                    });
121                }
122                let r = AnnouncementReference {
123                    original_network_id: u16::from_be_bytes([body[pos], body[pos + 1]]),
124                    transport_stream_id: u16::from_be_bytes([body[pos + 2], body[pos + 3]]),
125                    service_id: u16::from_be_bytes([body[pos + 4], body[pos + 5]]),
126                    component_tag: body[pos + 6],
127                };
128                pos += REFERENCE_LEN;
129                Some(r)
130            } else {
131                None
132            };
133            entries.push(AnnouncementEntry {
134                announcement_type,
135                reference_type,
136                reference,
137            });
138        }
139        Ok(Self {
140            announcement_support_indicator,
141            entries,
142        })
143    }
144}
145
146impl AnnouncementSupportDescriptor {
147    fn body_len(&self) -> usize {
148        INDICATOR_LEN
149            + self
150                .entries
151                .iter()
152                .map(|e| {
153                    TYPE_BYTE_LEN
154                        + if reference_present(e.reference_type) {
155                            REFERENCE_LEN
156                        } else {
157                            0
158                        }
159                })
160                .sum::<usize>()
161    }
162}
163
164impl Serialize for AnnouncementSupportDescriptor {
165    type Error = crate::error::Error;
166    fn serialized_len(&self) -> usize {
167        HEADER_LEN + self.body_len()
168    }
169
170    fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
171        for e in &self.entries {
172            if e.announcement_type > ANNOUNCEMENT_TYPE_MAX {
173                return Err(Error::InvalidDescriptor {
174                    tag: TAG,
175                    reason: "announcement_type exceeds 4 bits",
176                });
177            }
178            if e.reference_type > REFERENCE_TYPE_MAX {
179                return Err(Error::InvalidDescriptor {
180                    tag: TAG,
181                    reason: "reference_type exceeds 3 bits",
182                });
183            }
184            // A reference must be present exactly when reference_type ∈ {1,2,3}.
185            if reference_present(e.reference_type) != e.reference.is_some() {
186                return Err(Error::InvalidDescriptor {
187                    tag: TAG,
188                    reason: "reference presence does not match reference_type",
189                });
190            }
191        }
192        let body_len = self.body_len();
193        if body_len > u8::MAX as usize {
194            return Err(Error::InvalidDescriptor {
195                tag: TAG,
196                reason: "announcement_support_descriptor body exceeds 255 bytes",
197            });
198        }
199        let len = self.serialized_len();
200        if buf.len() < len {
201            return Err(Error::OutputBufferTooSmall {
202                need: len,
203                have: buf.len(),
204            });
205        }
206        buf[0] = TAG;
207        buf[1] = body_len as u8;
208        buf[HEADER_LEN..HEADER_LEN + INDICATOR_LEN]
209            .copy_from_slice(&self.announcement_support_indicator.to_be_bytes());
210        let mut pos = HEADER_LEN + INDICATOR_LEN;
211        for e in &self.entries {
212            // reserved_future_use bit emitted as 1 (§5.1).
213            let flags = ((e.announcement_type << ANNOUNCEMENT_TYPE_SHIFT) & ANNOUNCEMENT_TYPE_MASK)
214                | RESERVED_BIT_MASK
215                | (e.reference_type & REFERENCE_TYPE_MASK);
216            buf[pos] = flags;
217            pos += TYPE_BYTE_LEN;
218            if let Some(r) = &e.reference {
219                buf[pos..pos + 2].copy_from_slice(&r.original_network_id.to_be_bytes());
220                buf[pos + 2..pos + 4].copy_from_slice(&r.transport_stream_id.to_be_bytes());
221                buf[pos + 4..pos + 6].copy_from_slice(&r.service_id.to_be_bytes());
222                buf[pos + 6] = r.component_tag;
223                pos += REFERENCE_LEN;
224            }
225        }
226        Ok(len)
227    }
228}
229impl<'a> crate::traits::DescriptorDef<'a> for AnnouncementSupportDescriptor {
230    const TAG: u8 = TAG;
231    const NAME: &'static str = "ANNOUNCEMENT_SUPPORT";
232}
233
234#[cfg(test)]
235mod tests {
236    use super::*;
237
238    #[test]
239    fn parse_entry_without_reference() {
240        // indicator=0x0040, one entry: type=0x06 (event), reserved=1, ref_type=0x00 (usual audio)
241        // flags = 0110 1 000 = 0x68
242        let bytes = [TAG, 3, 0x00, 0x40, 0x68];
243        let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
244        assert_eq!(d.announcement_support_indicator, 0x0040);
245        assert_eq!(d.entries.len(), 1);
246        assert_eq!(d.entries[0].announcement_type, 0x06);
247        assert_eq!(d.entries[0].reference_type, 0x00);
248        assert!(d.entries[0].reference.is_none());
249    }
250
251    #[test]
252    fn parse_entry_with_reference() {
253        // indicator=0x0001, entry: type=0x01, ref_type=0x02 → reference present.
254        // flags = 0001 1 010 = 0x1A
255        let bytes = [
256            TAG, 10, 0x00, 0x01,
257            0x1A, // onid=0xAABB, tsid=0xCCDD, sid=0xEEFF, component_tag=0x09
258            0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x09,
259        ];
260        let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
261        assert_eq!(d.entries.len(), 1);
262        assert_eq!(d.entries[0].announcement_type, 0x01);
263        assert_eq!(d.entries[0].reference_type, 0x02);
264        let r = d.entries[0].reference.unwrap();
265        assert_eq!(r.original_network_id, 0xAABB);
266        assert_eq!(r.transport_stream_id, 0xCCDD);
267        assert_eq!(r.service_id, 0xEEFF);
268        assert_eq!(r.component_tag, 0x09);
269    }
270
271    #[test]
272    fn parse_mixed_entries() {
273        // entry1 ref_type=0 (no ref), entry2 ref_type=3 (ref present)
274        let bytes = [
275            TAG, 11, 0x12, 0x34, // indicator
276            0x40, // type=4 ref_type=0
277            0x53, // type=5 reserved=0 ref_type=3 -> 0101 0 011
278            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
279        ];
280        let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
281        assert_eq!(d.entries.len(), 2);
282        assert!(d.entries[0].reference.is_none());
283        assert_eq!(d.entries[1].reference_type, 0x03);
284        assert!(d.entries[1].reference.is_some());
285    }
286
287    #[test]
288    fn parse_ignores_reserved_bit() {
289        // reserved bit clear (0x60 vs 0x68): still parses.
290        let bytes = [TAG, 3, 0x00, 0x00, 0x60];
291        let d = AnnouncementSupportDescriptor::parse(&bytes).unwrap();
292        assert_eq!(d.entries[0].announcement_type, 0x06);
293        assert_eq!(d.entries[0].reference_type, 0x00);
294    }
295
296    #[test]
297    fn parse_rejects_wrong_tag() {
298        assert!(matches!(
299            AnnouncementSupportDescriptor::parse(&[0x6F, 2, 0, 0]).unwrap_err(),
300            Error::InvalidDescriptor { tag: 0x6F, .. }
301        ));
302    }
303
304    #[test]
305    fn parse_rejects_body_too_short_for_indicator() {
306        assert!(matches!(
307            AnnouncementSupportDescriptor::parse(&[TAG, 1, 0]).unwrap_err(),
308            Error::InvalidDescriptor { tag: TAG, .. }
309        ));
310    }
311
312    #[test]
313    fn parse_rejects_reference_truncated() {
314        // ref_type=1 but no reference bytes.
315        let bytes = [TAG, 3, 0x00, 0x00, 0x09]; // 0000 1 001
316        assert!(matches!(
317            AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
318            Error::InvalidDescriptor { tag: TAG, .. }
319        ));
320    }
321
322    #[test]
323    fn parse_rejects_buffer_shorter_than_length() {
324        let bytes = [TAG, 5, 0x00, 0x00];
325        assert!(matches!(
326            AnnouncementSupportDescriptor::parse(&bytes).unwrap_err(),
327            Error::BufferTooShort { .. }
328        ));
329    }
330
331    #[test]
332    fn serialize_round_trip_mixed() {
333        let d = AnnouncementSupportDescriptor {
334            announcement_support_indicator: 0xBEEF,
335            entries: vec![
336                AnnouncementEntry {
337                    announcement_type: 0x04,
338                    reference_type: 0x00,
339                    reference: None,
340                },
341                AnnouncementEntry {
342                    announcement_type: 0x01,
343                    reference_type: 0x02,
344                    reference: Some(AnnouncementReference {
345                        original_network_id: 0xAABB,
346                        transport_stream_id: 0xCCDD,
347                        service_id: 0xEEFF,
348                        component_tag: 0x09,
349                    }),
350                },
351            ],
352        };
353        let mut buf = vec![0u8; d.serialized_len()];
354        d.serialize_into(&mut buf).unwrap();
355        assert_eq!(AnnouncementSupportDescriptor::parse(&buf).unwrap(), d);
356    }
357
358    #[test]
359    fn serialize_rejects_too_small_buffer() {
360        let d = AnnouncementSupportDescriptor {
361            announcement_support_indicator: 0,
362            entries: vec![],
363        };
364        let mut buf = vec![0u8; 3];
365        assert!(matches!(
366            d.serialize_into(&mut buf).unwrap_err(),
367            Error::OutputBufferTooSmall { .. }
368        ));
369    }
370
371    #[test]
372    fn serialize_rejects_over_range_announcement_type() {
373        let d = AnnouncementSupportDescriptor {
374            announcement_support_indicator: 0,
375            entries: vec![AnnouncementEntry {
376                announcement_type: 0x10, // 5 bits
377                reference_type: 0,
378                reference: None,
379            }],
380        };
381        let mut buf = vec![0u8; d.serialized_len()];
382        assert!(matches!(
383            d.serialize_into(&mut buf).unwrap_err(),
384            Error::InvalidDescriptor { tag: TAG, .. }
385        ));
386    }
387
388    #[test]
389    fn serialize_rejects_reference_mismatch() {
390        // ref_type=2 demands a reference, but None supplied.
391        let d = AnnouncementSupportDescriptor {
392            announcement_support_indicator: 0,
393            entries: vec![AnnouncementEntry {
394                announcement_type: 0,
395                reference_type: 0x02,
396                reference: None,
397            }],
398        };
399        let mut buf = vec![0u8; d.serialized_len()];
400        assert!(matches!(
401            d.serialize_into(&mut buf).unwrap_err(),
402            Error::InvalidDescriptor { tag: TAG, .. }
403        ));
404    }
405
406    #[cfg(feature = "serde")]
407    #[test]
408    fn serde_round_trip() {
409        let d = AnnouncementSupportDescriptor {
410            announcement_support_indicator: 0xBEEF,
411            entries: vec![AnnouncementEntry {
412                announcement_type: 0x01,
413                reference_type: 0x02,
414                reference: Some(AnnouncementReference {
415                    original_network_id: 0xAABB,
416                    transport_stream_id: 0xCCDD,
417                    service_id: 0xEEFF,
418                    component_tag: 0x09,
419                }),
420            }],
421        };
422        let json = serde_json::to_string(&d).unwrap();
423        // Serialize-only: assert the emitted JSON re-parses (serialize-stable).
424        let _v: serde_json::Value = serde_json::from_str(&json).unwrap();
425    }
426}