1use crate::{
4 prelude::*,
5 utils::{pad_to_4bytes, parser, u16_from_be_bytes, writer},
6 RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9pub mod dlrr;
10pub mod duplicate_rle;
11pub mod loss_rle;
12pub mod packet_receipt_time;
13pub mod receiver_reference_time;
14pub(crate) mod rle;
15
16#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct Xr<'a> {
19 data: &'a [u8],
20}
21
22impl RtcpPacket for Xr<'_> {
23 const MIN_PACKET_LEN: usize = 12;
24 const PACKET_TYPE: u8 = 207;
25}
26
27impl<'a> RtcpPacketParser<'a> for Xr<'a> {
28 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
29 parser::check_packet::<Self>(data)?;
30 let mut offset = 8;
31 loop {
32 if offset >= data.len() {
33 break;
34 }
35 let block = XrBlock::parse(&data[offset..])?;
36 offset += block.length();
37 }
38 Ok(Self { data })
39 }
40
41 #[inline(always)]
42 fn header_data(&self) -> [u8; 4] {
43 self.data[..4].try_into().unwrap()
44 }
45}
46
47impl<'a> Xr<'a> {
48 pub fn builder() -> XrBuilder {
50 XrBuilder {
51 padding: 0,
52 sender_ssrc: 0,
53 blocks: vec![],
54 }
55 }
56
57 pub fn padding(&self) -> Option<u8> {
59 parser::parse_padding(self.data)
60 }
61
62 pub fn sender_ssrc(&self) -> u32 {
64 parser::parse_ssrc(self.data)
65 }
66
67 pub fn block_iter(&'a self) -> impl Iterator<Item = XrBlock<'a>> + 'a {
69 XrBlockIter {
70 xr: self,
71 offset: 8,
72 }
73 }
74 }
76
77struct XrBlockIter<'a> {
78 xr: &'a Xr<'a>,
79 offset: usize,
80}
81
82impl<'a> Iterator for XrBlockIter<'a> {
83 type Item = XrBlock<'a>;
84
85 fn next(&mut self) -> Option<Self::Item> {
86 if self.offset > self.xr.data.len() {
87 return None;
88 }
89 let block = XrBlock::parse(&self.xr.data[self.offset..]).ok()?;
90 self.offset += block.length();
91 Some(block)
92 }
93}
94
95#[derive(Debug)]
97#[must_use = "The builder must be built to be used"]
98pub struct XrBuilder {
99 padding: u8,
100 sender_ssrc: u32,
101 blocks: Vec<Box<dyn XrBlockBuilder<'static>>>,
102}
103
104impl XrBuilder {
105 pub fn sender_ssrc(mut self, sender_ssrc: u32) -> Self {
107 self.sender_ssrc = sender_ssrc;
108 self
109 }
110
111 pub fn padding(mut self, padding: u8) -> Self {
113 self.padding = padding;
114 self
115 }
116
117 pub fn add_block(mut self, block: impl XrBlockBuilder<'static> + 'static) -> XrBuilder {
119 self.blocks.push(Box::new(block));
120 self
121 }
122}
123
124impl RtcpPacketWriter for XrBuilder {
125 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
132 writer::check_padding(self.padding)?;
133
134 let mut len = 0;
135 for block in self.blocks.iter() {
136 len += pad_to_4bytes(block.calculate_size()?);
137 }
138
139 Ok(Xr::MIN_PACKET_LEN - 4 + len)
140 }
141
142 #[inline]
150 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
151 let mut idx = writer::write_header_unchecked::<Xr>(self.padding, 0, buf);
152 buf[idx..idx + 4].copy_from_slice(&self.sender_ssrc.to_be_bytes());
153 idx += 4;
154
155 for block in self.blocks.iter() {
156 let len = block.write_into_unchecked(&mut buf[idx..]);
157 let padded_len = pad_to_4bytes(len);
158 if len != padded_len {
159 buf[len..padded_len].fill(0);
160 }
161 idx += padded_len;
162 }
163 idx
164 }
165
166 fn get_padding(&self) -> Option<u8> {
167 if self.padding == 0 {
168 return None;
169 }
170
171 Some(self.padding)
172 }
173}
174
175#[derive(Debug)]
177pub struct XrBlock<'a> {
178 pub(crate) data: &'a [u8],
179}
180
181impl<'a> XrBlock<'a> {
182 pub fn parse_into<T: XrBlockParser<'a> + XrBlockStaticType>(
184 &self,
185 ) -> Result<T, RtcpParseError> {
186 if T::BLOCK_TYPE != self.block_type() {
187 return Err(RtcpParseError::WrongImplementation);
188 }
189 T::parse(self.data)
190 }
191}
192
193impl<'a> XrBlockParser<'a> for XrBlock<'a> {
194 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
195 if data.len() < 4 {
196 return Err(RtcpParseError::Truncated {
197 expected: 4,
198 actual: data.len(),
199 });
200 }
201 let ret = Self { data };
202 if data.len() < ret.length() {
203 return Err(RtcpParseError::Truncated {
204 expected: ret.length(),
205 actual: data.len(),
206 });
207 }
208
209 Ok(ret)
210 }
211
212 #[inline(always)]
213 fn header_data(&self) -> [u8; 4] {
214 self.data[..4].try_into().unwrap()
215 }
216}
217
218pub trait XrBlockParser<'a>: Sized {
224 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
226
227 fn header_data(&self) -> [u8; 4];
229}
230
231pub trait XrBlockParserExt<'a>: XrBlockParser<'a> {
233 fn block_type(&self) -> u8 {
235 self.header_data()[0]
236 }
237
238 fn type_specific_byte(&self) -> u8 {
240 self.header_data()[1]
241 }
242
243 fn length(&self) -> usize {
245 (u16_from_be_bytes(&self.header_data()[2..4]) as usize + 1) * 4
246 }
247}
248
249impl<'a, T: XrBlockParser<'a>> XrBlockParserExt<'a> for T {}
250
251pub trait XrBlockStaticType {
253 const BLOCK_TYPE: u8;
255}
256
257pub trait XrBlockBuilder<'a>: RtcpPacketWriter {
259 fn type_specific_byte(&self) -> u8;
261}
262
263pub trait XrBlockBuilderExt<'a>: XrBlockBuilder<'a> {
265 fn write_header_unchecked(&self, buf: &mut [u8], block_type: u8, block_word_len: u16) -> usize {
267 buf[0] = block_type;
268 buf[1] = self.type_specific_byte();
269 buf[2..4].copy_from_slice(&block_word_len.to_be_bytes());
270 4
271 }
272}
273
274impl<'a, T: XrBlockBuilder<'a>> XrBlockBuilderExt<'a> for T {}
275
276pub(crate) fn xr_offset_sequence(seq: u16, start: u16, end: u16, thinning: u8) -> Option<u16> {
277 let seq = seq
278 .wrapping_mul(2u16.pow(thinning as u32))
279 .wrapping_add(start);
280 if end <= start {
281 if seq < start && seq >= end {
282 None
283 } else {
284 Some(seq)
285 }
286 } else if seq >= end {
287 None
288 } else {
289 Some(seq)
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use duplicate_rle::DuplicateRle;
296 use loss_rle::LossRle;
297
298 use super::*;
299
300 #[test]
301 fn xr_block_build_single() {
302 let loss = LossRle::builder()
303 .ssrc(0x8642_1357)
304 .begin(100)
305 .end(200)
306 .thinning(0)
307 .add_chunk(rle::RleChunk::RunLength(100));
308 let builder = Xr::builder().sender_ssrc(0x8642_1357).add_block(loss);
309 let len = builder.calculate_size().unwrap();
310 let mut buf = vec![0; len];
311 builder.write_into_unchecked(&mut buf);
312 println!("{buf:x?}");
313
314 let xr = Xr::parse(&buf).unwrap();
315 assert_eq!(xr.sender_ssrc(), 0x8642_1357);
316 let mut it = xr.block_iter();
317 let rle = it.next().unwrap().parse_into::<LossRle>().unwrap();
318 assert_eq!(rle.thinning(), 0);
319 assert_eq!(rle.begin(), 100);
320 assert_eq!(rle.end(), 200);
321 }
322
323 #[test]
324 fn xr_block_build_2block() {
325 let loss = LossRle::builder()
326 .ssrc(0x8642_1357)
327 .begin(100)
328 .end(200)
329 .thinning(0)
330 .add_chunk(rle::RleChunk::RunLength(100));
331 let duplicate = DuplicateRle::builder()
332 .ssrc(0x8642_1357)
333 .begin(101)
334 .end(202)
335 .thinning(1)
336 .add_chunk(rle::RleChunk::SkipLength(100));
337 let builder = Xr::builder()
338 .sender_ssrc(0x8642_1357)
339 .add_block(loss)
340 .add_block(duplicate);
341 let len = builder.calculate_size().unwrap();
342 let mut buf = vec![0; len];
343 builder.write_into_unchecked(&mut buf);
344 println!("{buf:x?}");
345
346 let xr = Xr::parse(&buf).unwrap();
347 assert_eq!(xr.sender_ssrc(), 0x8642_1357);
348 let mut it = xr.block_iter();
349 let rle = it.next().unwrap().parse_into::<LossRle>().unwrap();
350 assert_eq!(rle.thinning(), 0);
351 assert_eq!(rle.begin(), 100);
352 assert_eq!(rle.end(), 200);
353 let rle = it.next().unwrap().parse_into::<DuplicateRle>().unwrap();
354 assert_eq!(rle.thinning(), 1);
355 assert_eq!(rle.begin(), 101);
356 assert_eq!(rle.end(), 202);
357 }
358
359 #[test]
360 fn xr_block_parse_truncated_header() {
361 let data = [1, 0, 0];
362 assert!(matches!(
363 XrBlock::parse(&data),
364 Err(RtcpParseError::Truncated {
365 expected: 4,
366 actual: 3
367 })
368 ));
369 }
370
371 #[test]
372 fn xr_block_parse_truncated_block() {
373 let data = [1, 0, 0, 1, 4, 2, 3];
374 assert!(matches!(
375 XrBlock::parse(&data),
376 Err(RtcpParseError::Truncated {
377 expected: 8,
378 actual: 7
379 })
380 ));
381 }
382
383 #[test]
384 fn xr_offset_at_start() {
385 for thinning in 0..15 {
386 assert_eq!(xr_offset_sequence(0, 100, 200, thinning), Some(100));
387 assert_eq!(
388 xr_offset_sequence(0, u16::MAX - 100, 200, thinning),
389 Some(u16::MAX - 100)
390 );
391 }
392 }
393
394 #[test]
395 fn xr_offset_at_end() {
396 assert_eq!(xr_offset_sequence(99, 100, 200, 0), Some(199));
397 assert_eq!(xr_offset_sequence(100, 100, 200, 0), None);
398
399 assert_eq!(xr_offset_sequence(99, u16::MAX - 49, 50, 0), Some(49));
400 assert_eq!(xr_offset_sequence(100, u16::MAX - 49, 50, 0), None);
401 }
402
403 #[test]
404 fn xr_offset_thinning() {
405 assert_eq!(xr_offset_sequence(49, 100, 200, 1), Some(198));
406 assert_eq!(xr_offset_sequence(50, 100, 200, 1), None);
407 assert_eq!(xr_offset_sequence(24, 100, 200, 2), Some(196));
408 assert_eq!(xr_offset_sequence(25, 100, 200, 2), None);
409
410 assert_eq!(xr_offset_sequence(49, u16::MAX - 49, 50, 1), Some(48));
411 assert_eq!(xr_offset_sequence(50, u16::MAX - 49, 50, 1), None);
412 assert_eq!(xr_offset_sequence(24, u16::MAX - 49, 50, 2), Some(46));
413 assert_eq!(xr_offset_sequence(25, u16::MAX - 49, 50, 2), None);
414 }
415}