rtcp_types/
sender.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use crate::{
4    prelude::*,
5    utils::{parser, u32_from_be_bytes, u64_from_be_bytes, writer},
6    ReportBlock, ReportBlockBuilder, RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9/// A Parsed Sender Report packet.
10#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct SenderReport<'a> {
12    data: &'a [u8],
13}
14
15impl RtcpPacket for SenderReport<'_> {
16    const MIN_PACKET_LEN: usize = 28;
17    const PACKET_TYPE: u8 = 200;
18}
19
20impl<'a> RtcpPacketParser<'a> for SenderReport<'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> SenderReport<'a> {
43    const MAX_REPORTS: u8 = Self::MAX_COUNT;
44
45    /// The (optional) padding used by this [`SenderReport`] 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    /// The 32.32 fixed point NTP timestamp sampled at the same time as the RTP timestamp
61    pub fn ntp_timestamp(&self) -> u64 {
62        u64_from_be_bytes(&self.data[8..16])
63    }
64
65    /// The RTP timestamp for this SSRC sampled at the same time as the NTP timestamp
66    pub fn rtp_timestamp(&self) -> u32 {
67        u32_from_be_bytes(&self.data[16..20])
68    }
69
70    /// The number of packets that this sender has sent
71    pub fn packet_count(&self) -> u32 {
72        u32_from_be_bytes(&self.data[20..24])
73    }
74
75    /// The number of octets (bytes) that this sender has sent
76    pub fn octet_count(&self) -> u32 {
77        u32_from_be_bytes(&self.data[24..28])
78    }
79
80    /// Iterator of report blocks in this [`SenderReport`]
81    pub fn report_blocks(&self) -> impl Iterator<Item = ReportBlock<'a>> + '_ {
82        self.data[Self::MIN_PACKET_LEN..Self::MIN_PACKET_LEN + (self.n_reports() as usize * 24)]
83            .chunks_exact(24)
84            .map(|b| ReportBlock::parse(b).unwrap())
85    }
86
87    /// Create a new [`SenderReportBuilder`]
88    pub fn builder(ssrc: u32) -> SenderReportBuilder {
89        SenderReportBuilder::new(ssrc)
90    }
91}
92
93/// Sender Report Builder
94#[derive(Debug)]
95#[must_use = "The builder must be built to be used"]
96pub struct SenderReportBuilder {
97    ssrc: u32,
98    padding: u8,
99    ntp_timestamp: u64,
100    rtp_timestamp: u32,
101    packet_count: u32,
102    octet_count: u32,
103    report_blocks: Vec<ReportBlockBuilder>,
104}
105
106impl SenderReportBuilder {
107    fn new(ssrc: u32) -> Self {
108        SenderReportBuilder {
109            ssrc,
110            padding: 0,
111            ntp_timestamp: 0,
112            rtp_timestamp: 0,
113            packet_count: 0,
114            octet_count: 0,
115            report_blocks: Vec::with_capacity(SenderReport::MAX_REPORTS as usize),
116        }
117    }
118
119    /// Sets the number of padding bytes to use for this Sender Report.
120    pub fn padding(mut self, padding: u8) -> Self {
121        self.padding = padding;
122        self
123    }
124
125    /// Sets the ntp_timestamp for this Sender Report.
126    pub fn ntp_timestamp(mut self, ntp_timestamp: u64) -> Self {
127        self.ntp_timestamp = ntp_timestamp;
128        self
129    }
130
131    /// Sets the ntp_timestamp for this Sender Report.
132    pub fn rtp_timestamp(mut self, rtp_timestamp: u32) -> Self {
133        self.rtp_timestamp = rtp_timestamp;
134        self
135    }
136
137    /// Sets the packet_count for this Sender Report.
138    pub fn packet_count(mut self, packet_count: u32) -> Self {
139        self.packet_count = packet_count;
140        self
141    }
142
143    /// Sets the octet_count for this Sender Report.
144    pub fn octet_count(mut self, octet_count: u32) -> Self {
145        self.octet_count = octet_count;
146        self
147    }
148
149    /// Adds the provided Report Block.
150    pub fn add_report_block(mut self, report_block: ReportBlockBuilder) -> Self {
151        self.report_blocks.push(report_block);
152        self
153    }
154}
155
156impl RtcpPacketWriter for SenderReportBuilder {
157    /// Calculates the size required to write this Sender Report packet.
158    ///
159    /// Returns an error if:
160    ///
161    /// * Too many Report Blocks where added.
162    /// * A Report Block is erroneous.
163    /// * The padding is not a multiple of 4.
164    fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
165        if self.report_blocks.len() > SenderReport::MAX_REPORTS as usize {
166            return Err(RtcpWriteError::TooManyReportBlocks {
167                count: self.report_blocks.len(),
168                max: SenderReport::MAX_REPORTS,
169            });
170        }
171
172        writer::check_padding(self.padding)?;
173
174        let mut report_blocks_size = 0;
175        for rb in self.report_blocks.iter() {
176            report_blocks_size += rb.calculate_size()?;
177        }
178
179        Ok(SenderReport::MIN_PACKET_LEN + report_blocks_size + self.padding as usize)
180    }
181
182    /// Write this Sender Report into `buf` without any validity checks.
183    ///
184    /// Uses the length of the buffer for the length field.
185    ///
186    /// Returns the number of bytes written.
187    ///
188    /// # Panic
189    ///
190    /// Panics if the buf is not large enough.
191    #[inline]
192    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
193        writer::write_header_unchecked::<SenderReport>(
194            self.padding,
195            self.report_blocks.len() as u8,
196            buf,
197        );
198
199        buf[4..8].copy_from_slice(&self.ssrc.to_be_bytes());
200        buf[8..16].copy_from_slice(&self.ntp_timestamp.to_be_bytes());
201        buf[16..20].copy_from_slice(&self.rtp_timestamp.to_be_bytes());
202        buf[20..24].copy_from_slice(&self.packet_count.to_be_bytes());
203        buf[24..28].copy_from_slice(&self.octet_count.to_be_bytes());
204
205        let mut idx = 28;
206        let mut end = idx;
207        for report_block in self.report_blocks.iter() {
208            end += ReportBlock::EXPECTED_SIZE;
209            report_block.write_into_unchecked(&mut buf[idx..end]);
210            idx = end;
211        }
212
213        end += writer::write_padding_unchecked(self.padding, &mut buf[idx..]);
214
215        end
216    }
217
218    fn get_padding(&self) -> Option<u8> {
219        if self.padding == 0 {
220            return None;
221        }
222
223        Some(self.padding)
224    }
225}
226
227#[cfg(test)]
228mod tests {
229    use super::*;
230
231    #[test]
232    fn parse_sr_no_report_blocks() {
233        let data = [
234            0x80, // VERSION | PADDING | N_REPORTS
235            0xc8, // PT=SR
236            0x00, 0x06, // LENGTH
237            0x01, 0x23, 0x45, 0x67, // SSRC
238            0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, // NTP timestamp
239            0x8a, 0xac, 0xce, 0xe0, // RTP timestamp
240            0xf1, 0xe2, 0xd3, 0xc4, // packet count
241            0xb5, 0xa6, 0x97, 0x88, // octet count
242        ];
243        let sr = SenderReport::parse(&data).unwrap();
244        assert_eq!(sr.version(), 2);
245        assert_eq!(sr.padding(), None);
246        assert_eq!(sr.n_reports(), 0);
247        assert_eq!(sr.ssrc(), 0x01234567);
248        assert_eq!(sr.ntp_timestamp(), 0x89abcdef02244668);
249        assert_eq!(sr.rtp_timestamp(), 0x8aaccee0);
250        assert_eq!(sr.packet_count(), 0xf1e2d3c4);
251        assert_eq!(sr.octet_count(), 0xb5a69788);
252    }
253
254    #[test]
255    fn build_empty_sr() {
256        const REQ_LEN: usize = SenderReport::MIN_PACKET_LEN;
257        let srb = SenderReport::builder(0x01234567)
258            .ntp_timestamp(0x89abcdef02244668)
259            .rtp_timestamp(0x8aaccee0)
260            .packet_count(0xf1e2d3c4)
261            .octet_count(0xb5a69788);
262        let req_len = srb.calculate_size().unwrap();
263        assert_eq!(req_len, REQ_LEN);
264
265        let mut data = [0; REQ_LEN];
266        let len = srb.write_into(&mut data).unwrap();
267        assert_eq!(len, REQ_LEN);
268        assert_eq!(
269            data,
270            [
271                0x80, // VERSION | PADDING | N_REPORTS
272                0xc8, // PT=SR
273                0x00, 0x06, // LENGTH
274                0x01, 0x23, 0x45, 0x67, // SSRC
275                0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, // NTP timestamp
276                0x8a, 0xac, 0xce, 0xe0, // RTP timestamp
277                0xf1, 0xe2, 0xd3, 0xc4, // packet count
278                0xb5, 0xa6, 0x97, 0x88, // octet count
279            ]
280        );
281    }
282
283    #[test]
284    fn build_2_blocks_sr() {
285        let rb1 = ReportBlock::builder(0x1234567);
286        let rb2 = ReportBlock::builder(0x1234568);
287
288        const REQ_LEN: usize = SenderReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2;
289        let srb = SenderReport::builder(0x91827364)
290            .ntp_timestamp(0x89abcdef02244668)
291            .rtp_timestamp(0x8aaccee0)
292            .packet_count(0xf1e2d3c4)
293            .octet_count(0xb5a69788)
294            .add_report_block(rb1)
295            .add_report_block(rb2);
296
297        let req_len = srb.calculate_size().unwrap();
298        assert_eq!(req_len, REQ_LEN);
299
300        let mut data = [0; REQ_LEN];
301        let len = srb.write_into(&mut data).unwrap();
302        assert_eq!(len, REQ_LEN);
303        assert_eq!(
304            data,
305            [
306                0x82, 0xc8, 0x00, 0x12, 0x91, 0x82, 0x73, 0x64, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24,
307                0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88,
308                0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68,
310                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311                0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312            ]
313        );
314    }
315
316    #[test]
317    fn build_2_blocks_padded_sr() {
318        let rb1 = ReportBlock::builder(0x1234567);
319        let rb2 = ReportBlock::builder(0x1234568);
320
321        const PADDING: usize = 4;
322        const REQ_LEN: usize =
323            SenderReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2 + PADDING;
324        let srb = SenderReport::builder(0x91827364)
325            .padding(PADDING as u8)
326            .add_report_block(rb1)
327            .add_report_block(rb2);
328
329        let req_len = srb.calculate_size().unwrap();
330        assert_eq!(req_len, REQ_LEN);
331
332        let mut data = [0; REQ_LEN];
333        let len = srb.write_into(&mut data).unwrap();
334        assert_eq!(len, REQ_LEN);
335        assert_eq!(
336            data,
337            [
338                0xa2, 0xc8, 0x00, 0x13, 0x91, 0x82, 0x73, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
339                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
340                0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
341                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68,
342                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
343                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
344            ]
345        );
346    }
347
348    #[test]
349    fn parse_sr_short() {
350        assert_eq!(
351            SenderReport::parse(&[0x80]),
352            Err(RtcpParseError::Truncated {
353                expected: 28,
354                actual: 1
355            })
356        );
357    }
358
359    #[test]
360    fn parse_sr_too_short_for_report_count() {
361        assert_eq!(
362            SenderReport::parse(&[
363                0x82, 0xc8, 0x00, 0x12, 0x91, 0x82, 0x73, 0x64, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24,
364                0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88,
365                0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
366                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
367            ]),
368            Err(RtcpParseError::Truncated {
369                expected: 76,
370                actual: 53
371            })
372        );
373    }
374
375    #[test]
376    fn build_too_many_report_blocks() {
377        let mut b = SenderReport::builder(0);
378        for _ in 0..SenderReport::MAX_REPORTS as usize + 1 {
379            b = b.add_report_block(ReportBlock::builder(1));
380        }
381        let err = b.calculate_size().unwrap_err();
382        assert_eq!(
383            err,
384            RtcpWriteError::TooManyReportBlocks {
385                count: SenderReport::MAX_REPORTS as usize + 1,
386                max: SenderReport::MAX_REPORTS
387            }
388        );
389    }
390
391    #[test]
392    fn build_erroneous_report() {
393        let b = SenderReport::builder(0)
394            .add_report_block(ReportBlock::builder(1).cumulative_lost(0xffffff + 1));
395        let err = b.calculate_size().unwrap_err();
396        assert_eq!(
397            err,
398            RtcpWriteError::CumulativeLostTooLarge {
399                value: 0xffffff + 1,
400                max: 0xffffff,
401            }
402        );
403    }
404
405    #[test]
406    fn build_padding_not_multiple_4() {
407        let b = SenderReport::builder(0).padding(5);
408        let err = b.calculate_size().unwrap_err();
409        assert_eq!(err, RtcpWriteError::InvalidPadding { padding: 5 });
410    }
411
412    #[test]
413    fn parse_sr_with_2_rb() {
414        let sr = SenderReport::parse(&[
415            0x82, 0xc8, 0x00, 0x12, 0x91, 0x82, 0x73, 0x64, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24,
416            0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88,
417            0x01, 0x23, 0x45, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68,
419            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
420            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421        ])
422        .unwrap();
423        assert_eq!(sr.version(), 2);
424        assert_eq!(sr.padding(), None);
425        assert_eq!(sr.n_reports(), 2);
426        assert_eq!(sr.length(), 76);
427        assert_eq!(sr.ssrc(), 0x91827364);
428        assert_eq!(sr.ntp_timestamp(), 0x89abcdef02244668);
429        assert_eq!(sr.rtp_timestamp(), 0x8aaccee0);
430        assert_eq!(sr.packet_count(), 0xf1e2d3c4);
431        assert_eq!(sr.octet_count(), 0xb5a69788);
432        let mut rb = sr.report_blocks();
433        let rb_item = rb.next().unwrap();
434        assert_eq!(rb_item.ssrc(), 0x01234567);
435        let rb_item = rb.next().unwrap();
436        assert_eq!(rb_item.ssrc(), 0x01234568);
437        assert_eq!(rb.next(), None);
438    }
439}