Skip to main content

dvb_si/collect/
bat.rs

1use crate::descriptors::DescriptorRegistry;
2use crate::tables::bat;
3use alloc::vec::Vec;
4
5use super::{CompleteSectionSet, CompleteTransportStream, ParsedDescriptorLoop};
6
7/// Complete logical Bouquet Association Table.
8#[derive(Debug)]
9#[non_exhaustive]
10pub struct CompleteBat<'a> {
11    /// Bouquet identifier.
12    pub bouquet_id: u16,
13    /// 5-bit version_number.
14    pub version_number: u8,
15    /// current_next_indicator bit.
16    pub current_next_indicator: bool,
17    /// Bouquet descriptors, concatenated across every section that carries a
18    /// `bouquet_descriptors_loop` (EN 300 468 ยง5.2.2: each section has its
19    /// own loop, so a bouquet name/linkage split across sections is not
20    /// lost).
21    pub bouquet_descriptors: ParsedDescriptorLoop<'a>,
22    /// Transport-stream loop entries from all sections in wire order.
23    pub transport_streams: Vec<CompleteTransportStream<'a>>,
24}
25
26impl<'a> CompleteBat<'a> {
27    pub(crate) fn parse(
28        set: &'a CompleteSectionSet,
29        registry: Option<&'a DescriptorRegistry>,
30    ) -> crate::Result<Self> {
31        let sections: Vec<bat::BatSection<'a>> = set.parse_sections()?;
32        let first = sections.first().ok_or(crate::Error::BufferTooShort(
33            broadcast_common::error::BufferTooShort {
34                need: 1,
35                have: 0,
36                what: "CompleteBat sections",
37            },
38        ))?;
39        let transport_streams = CompleteTransportStream::collect(
40            sections.iter().flat_map(|section| {
41                section.transport_streams.iter().map(|ts| {
42                    (
43                        ts.transport_stream_id,
44                        ts.original_network_id,
45                        ts.descriptors,
46                    )
47                })
48            }),
49            registry,
50        );
51        Ok(Self {
52            bouquet_id: first.bouquet_id,
53            version_number: first.version_number,
54            current_next_indicator: first.current_next_indicator,
55            bouquet_descriptors: ParsedDescriptorLoop::parse_all(
56                sections.iter().map(|section| section.bouquet_descriptors),
57                registry,
58            ),
59            transport_streams,
60        })
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::super::SectionSetCollector;
67    use crate::descriptors::DescriptorLoop;
68    use crate::tables::bat::BatSection;
69
70    fn build_bat_section(
71        bouquet_id: u16,
72        version: u8,
73        section_number: u8,
74        last_section_number: u8,
75        bouquet_desc: &[u8],
76        ts_entries: &[(u16, u16, &[u8])],
77    ) -> Vec<u8> {
78        use broadcast_common::Serialize;
79        let bat = BatSection::new(
80            bouquet_id,
81            version,
82            true,
83            section_number,
84            last_section_number,
85            DescriptorLoop::new(bouquet_desc),
86            ts_entries
87                .iter()
88                .map(|(tsid, onid, desc)| {
89                    crate::tables::TransportStreamEntry::new(
90                        *tsid,
91                        *onid,
92                        DescriptorLoop::new(desc),
93                    )
94                })
95                .collect(),
96        );
97        let mut buf = vec![0u8; bat.serialized_len()];
98        bat.serialize_into(&mut buf).unwrap();
99        buf
100    }
101
102    #[test]
103    fn complete_bat_preserves_bouquet_descriptors_and_ts_entries() {
104        let bouquet_name = [0x47u8, 0x03, b'F', b'o', b'o'];
105        let ts_desc = [0x43u8, 0x01, 0x01];
106
107        let sec = build_bat_section(
108            0x1234,
109            3,
110            0,
111            0,
112            &bouquet_name,
113            &[(0x1001, 0x2002, &ts_desc)],
114        );
115
116        let mut collector = SectionSetCollector::new();
117        let set = collector.push_section(&sec).unwrap().unwrap();
118        let complete = set.bat().unwrap();
119
120        assert_eq!(complete.bouquet_id, 0x1234);
121        assert_eq!(complete.version_number, 3);
122        assert!(complete.current_next_indicator);
123        assert_eq!(complete.transport_streams.len(), 1);
124        assert_eq!(complete.transport_streams[0].transport_stream_id, 0x1001);
125        assert_eq!(complete.transport_streams[0].original_network_id, 0x2002);
126    }
127}