1use crate::{
4 prelude::*,
5 utils::{parser, u32_from_be_bytes, u64_from_be_bytes, writer},
6 ReportBlock, ReportBlockBuilder, RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9#[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 pub fn padding(&self) -> Option<u8> {
47 parser::parse_padding(self.data)
48 }
49
50 pub fn n_reports(&self) -> u8 {
52 self.count()
53 }
54
55 pub fn ssrc(&self) -> u32 {
57 parser::parse_ssrc(self.data)
58 }
59
60 pub fn ntp_timestamp(&self) -> u64 {
62 u64_from_be_bytes(&self.data[8..16])
63 }
64
65 pub fn rtp_timestamp(&self) -> u32 {
67 u32_from_be_bytes(&self.data[16..20])
68 }
69
70 pub fn packet_count(&self) -> u32 {
72 u32_from_be_bytes(&self.data[20..24])
73 }
74
75 pub fn octet_count(&self) -> u32 {
77 u32_from_be_bytes(&self.data[24..28])
78 }
79
80 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 pub fn builder(ssrc: u32) -> SenderReportBuilder {
89 SenderReportBuilder::new(ssrc)
90 }
91}
92
93#[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 pub fn padding(mut self, padding: u8) -> Self {
121 self.padding = padding;
122 self
123 }
124
125 pub fn ntp_timestamp(mut self, ntp_timestamp: u64) -> Self {
127 self.ntp_timestamp = ntp_timestamp;
128 self
129 }
130
131 pub fn rtp_timestamp(mut self, rtp_timestamp: u32) -> Self {
133 self.rtp_timestamp = rtp_timestamp;
134 self
135 }
136
137 pub fn packet_count(mut self, packet_count: u32) -> Self {
139 self.packet_count = packet_count;
140 self
141 }
142
143 pub fn octet_count(mut self, octet_count: u32) -> Self {
145 self.octet_count = octet_count;
146 self
147 }
148
149 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 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 #[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, 0xc8, 0x00, 0x06, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88, ];
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, 0xc8, 0x00, 0x06, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, 0x8a, 0xac, 0xce, 0xe0, 0xf1, 0xe2, 0xd3, 0xc4, 0xb5, 0xa6, 0x97, 0x88, ]
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}