rtcp_types/
receiver.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use crate::{
4    prelude::*,
5    utils::{parser, writer},
6    ReportBlock, ReportBlockBuilder, RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9/// A Parsed Receiver Report packet.
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct ReceiverReport<'a> {
12    data: &'a [u8],
13}
14
15impl RtcpPacket for ReceiverReport<'_> {
16    const MIN_PACKET_LEN: usize = 8;
17    const PACKET_TYPE: u8 = 201;
18}
19
20impl<'a> RtcpPacketParser<'a> for ReceiverReport<'a> {
21    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
22        parser::check_packet::<Self>(data)?;
23
24        let req_len =
25            Self::MIN_PACKET_LEN + parser::parse_count(data) as usize * ReportBlock::EXPECTED_SIZE;
26        if data.len() < req_len {
27            return Err(RtcpParseError::Truncated {
28                expected: req_len,
29                actual: data.len(),
30            });
31        }
32
33        Ok(Self { data })
34    }
35
36    #[inline(always)]
37    fn header_data(&self) -> [u8; 4] {
38        self.data[..4].try_into().unwrap()
39    }
40}
41
42impl<'a> ReceiverReport<'a> {
43    const MAX_REPORTS: u8 = Self::MAX_COUNT;
44
45    /// The (optional) padding used by this [`ReceiverReport`] packet
46    pub fn padding(&self) -> Option<u8> {
47        parser::parse_padding(self.data)
48    }
49
50    /// The number of reports contained in this packet
51    pub fn n_reports(&self) -> u8 {
52        self.count()
53    }
54
55    /// The SSRC of the entity providing the report
56    pub fn ssrc(&self) -> u32 {
57        parser::parse_ssrc(self.data)
58    }
59
60    /// Iterator of report blocks in this [`ReceiverReport`]
61    pub fn report_blocks(&self) -> impl Iterator<Item = ReportBlock<'a>> + '_ {
62        self.data[Self::MIN_PACKET_LEN..Self::MIN_PACKET_LEN + (self.n_reports() as usize * 24)]
63            .chunks_exact(24)
64            .map(|b| ReportBlock::parse(b).unwrap())
65    }
66
67    /// Create a new [`ReportBlockBuilder`]
68    pub fn builder(ssrc: u32) -> ReceiverReportBuilder {
69        ReceiverReportBuilder::new(ssrc)
70    }
71}
72
73/// Receiver Report Builder
74#[derive(Debug)]
75#[must_use = "The builder must be built to be used"]
76pub struct ReceiverReportBuilder {
77    ssrc: u32,
78    padding: u8,
79    report_blocks: Vec<ReportBlockBuilder>,
80}
81
82impl ReceiverReportBuilder {
83    fn new(ssrc: u32) -> Self {
84        ReceiverReportBuilder {
85            ssrc,
86            padding: 0,
87            report_blocks: Vec::with_capacity(ReceiverReport::MAX_REPORTS as usize),
88        }
89    }
90
91    /// Sets the number of padding bytes to use for this receiver report.
92    pub fn padding(mut self, padding: u8) -> Self {
93        self.padding = padding;
94        self
95    }
96
97    /// Adds the provided Report Block.
98    pub fn add_report_block(mut self, report_block: ReportBlockBuilder) -> Self {
99        self.report_blocks.push(report_block);
100        self
101    }
102}
103
104impl RtcpPacketWriter for ReceiverReportBuilder {
105    /// Calculates the size required to write this Receiver Report packet.
106    ///
107    /// Returns an error if:
108    ///
109    /// * Too many Report Blocks where added.
110    /// * A Report Block is erroneous.
111    /// * The padding is not a multiple of 4.
112    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
113        if self.report_blocks.len() > ReceiverReport::MAX_REPORTS as usize {
114            return Err(RtcpWriteError::TooManyReportBlocks {
115                count: self.report_blocks.len(),
116                max: ReceiverReport::MAX_REPORTS,
117            });
118        }
119
120        writer::check_padding(self.padding)?;
121
122        let mut report_blocks_size = 0;
123        for rb in self.report_blocks.iter() {
124            report_blocks_size += rb.calculate_size()?;
125        }
126
127        Ok(ReceiverReport::MIN_PACKET_LEN + report_blocks_size + self.padding as usize)
128    }
129
130    /// Writes this Receiver Report into `buf` without any validity checks.
131    ///
132    /// Uses the length of the buffer for the length field.
133    ///
134    /// Returns the number of bytes written.
135    ///
136    /// # Panic
137    ///
138    /// Panics if the buf is not large enough.
139    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
140        writer::write_header_unchecked::<ReceiverReport>(
141            self.padding,
142            self.report_blocks.len() as u8,
143            buf,
144        );
145
146        buf[4..8].copy_from_slice(&self.ssrc.to_be_bytes());
147
148        let mut idx = 8;
149        let mut end = idx;
150        for report_block in self.report_blocks.iter() {
151            end += ReportBlock::EXPECTED_SIZE;
152            report_block.write_into_unchecked(&mut buf[idx..end]);
153            idx = end;
154        }
155
156        end += writer::write_padding_unchecked(self.padding, &mut buf[idx..]);
157
158        end
159    }
160
161    fn get_padding(&self) -> Option<u8> {
162        if self.padding == 0 {
163            return None;
164        }
165
166        Some(self.padding)
167    }
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    #[test]
175    fn parse_empty_rr() {
176        let data = [0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64];
177        let rr = ReceiverReport::parse(&data).unwrap();
178        assert_eq!(rr.version(), 2);
179        assert_eq!(rr.padding(), None);
180        assert_eq!(rr.n_reports(), 0);
181        assert_eq!(rr.report_blocks().count(), 0);
182    }
183
184    #[test]
185    fn build_empty_rr() {
186        const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN;
187        let rrb = ReceiverReport::builder(0x91827364);
188        let req_len = rrb.calculate_size().unwrap();
189        assert_eq!(req_len, REQ_LEN);
190
191        let mut data = [0; REQ_LEN];
192        let len = rrb.write_into(&mut data).unwrap();
193        assert_eq!(len, REQ_LEN);
194        assert_eq!(data, [0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64]);
195    }
196
197    #[test]
198    fn build_2_blocks_rr() {
199        let rb1 = ReportBlock::builder(0x1234567);
200        let rb2 = ReportBlock::builder(0x1234568);
201
202        const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2;
203        let rrb = ReceiverReport::builder(0x91827364)
204            .add_report_block(rb1)
205            .add_report_block(rb2);
206        let req_len = rrb.calculate_size().unwrap();
207        assert_eq!(req_len, REQ_LEN);
208
209        let mut data = [0; REQ_LEN];
210        let len = rrb.write_into(&mut data).unwrap();
211        assert_eq!(len, REQ_LEN);
212        assert_eq!(
213            data,
214            [
215                0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
216                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217                0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219            ]
220        );
221    }
222
223    #[test]
224    fn build_2_blocks_padded_rr() {
225        let rb1 = ReportBlock::builder(0x1234567);
226        let rb2 = ReportBlock::builder(0x1234568);
227
228        const PADDING: usize = 4;
229        const REQ_LEN: usize =
230            ReceiverReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2 + PADDING;
231        let rrb = ReceiverReport::builder(0x91827364)
232            .padding(PADDING as u8)
233            .add_report_block(rb1)
234            .add_report_block(rb2);
235        let req_len = rrb.calculate_size().unwrap();
236        assert_eq!(req_len, REQ_LEN);
237
238        let mut data = [0; REQ_LEN];
239        let len = rrb.write_into(&mut data).unwrap();
240        assert_eq!(len, REQ_LEN);
241        assert_eq!(
242            data,
243            [
244                0xa2, 0xc9, 0x00, 0x0e, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
245                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246                0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248                0x00, 0x00, 0x00, 0x04,
249            ]
250        );
251    }
252
253    #[test]
254    fn parse_rr_with_2_rb() {
255        let rr = ReceiverReport::parse(&[
256            0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
257            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258            0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260        ])
261        .unwrap();
262        assert_eq!(rr.version(), 2);
263        assert_eq!(rr.padding(), None);
264        assert_eq!(rr.n_reports(), 2);
265        assert_eq!(rr.length(), 56);
266        assert_eq!(rr.ssrc(), 0x91827364);
267        let mut rb = rr.report_blocks();
268        let rb_item = rb.next().unwrap();
269        assert_eq!(rb_item.ssrc(), 0x01234567);
270        let rb_item = rb.next().unwrap();
271        assert_eq!(rb_item.ssrc(), 0x01234568);
272        assert_eq!(rb.next(), None);
273    }
274
275    #[test]
276    fn parse_rr_short() {
277        assert_eq!(
278            ReceiverReport::parse(&[0]),
279            Err(RtcpParseError::Truncated {
280                expected: 8,
281                actual: 1
282            })
283        );
284    }
285
286    #[test]
287    fn parse_sr_too_short_for_report_count() {
288        assert_eq!(
289            ReceiverReport::parse(&[
290                0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
291                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292                0x00, 0x00, 0x00, 0x00,
293            ]),
294            Err(RtcpParseError::Truncated {
295                expected: 56,
296                actual: 32
297            })
298        );
299    }
300
301    #[test]
302    fn build_too_many_report_blocks() {
303        let mut b = ReceiverReport::builder(0);
304        for _ in 0..ReceiverReport::MAX_REPORTS as usize + 1 {
305            b = b.add_report_block(ReportBlock::builder(1));
306        }
307        let err = b.calculate_size().unwrap_err();
308        assert_eq!(
309            err,
310            RtcpWriteError::TooManyReportBlocks {
311                count: ReceiverReport::MAX_REPORTS as usize + 1,
312                max: ReceiverReport::MAX_REPORTS
313            }
314        );
315    }
316
317    #[test]
318    fn build_erroneous_report() {
319        let b = ReceiverReport::builder(0)
320            .add_report_block(ReportBlock::builder(1).cumulative_lost(0xffffff + 1));
321        let err = b.calculate_size().unwrap_err();
322        assert_eq!(
323            err,
324            RtcpWriteError::CumulativeLostTooLarge {
325                value: 0xffffff + 1,
326                max: 0xffffff,
327            }
328        );
329    }
330
331    #[test]
332    fn build_padding_not_multiple_4() {
333        let b = ReceiverReport::builder(0).padding(5);
334        let err = b.calculate_size().unwrap_err();
335        assert_eq!(err, RtcpWriteError::InvalidPadding { padding: 5 });
336    }
337}