rtcp_types/xr/
loss_rle.rs1use crate::prelude::*;
4use crate::xr::rle::{Rle, RleBuilder, RleChunk};
5use crate::xr::{XrBlockBuilder, XrBlockParser};
6use crate::{RtcpParseError, RtcpWriteError};
7
8use super::XrBlockStaticType;
9
10#[derive(Debug)]
12pub struct LossRle<'a> {
13 rle: Rle<'a>,
14}
15
16impl XrBlockStaticType for LossRle<'_> {
17 const BLOCK_TYPE: u8 = 0x1;
18}
19
20impl<'a> XrBlockParser<'a> for LossRle<'a> {
21 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
22 let rle = Rle::parse(data)?;
23 let ret = Self { rle };
24 Ok(ret)
25 }
26
27 #[inline(always)]
28 fn header_data(&self) -> [u8; 4] {
29 self.rle.block.header_data()
30 }
31}
32
33impl LossRle<'_> {
34 pub fn thinning(&self) -> u8 {
37 self.rle.thinning()
38 }
39
40 pub fn media_ssrc(&self) -> u32 {
42 self.rle.media_ssrc()
43 }
44
45 pub fn begin(&self) -> u16 {
48 self.rle.begin()
49 }
50
51 pub fn end(&self) -> u16 {
54 self.rle.end()
55 }
56
57 pub fn sequence_iter(&self) -> impl Iterator<Item = u16> + '_ {
59 self.rle.sequence_iter()
60 }
61
62 pub fn chunk_iter(&self) -> impl Iterator<Item = RleChunk> + '_ {
67 self.rle.chunk_iter()
68 }
69
70 pub fn builder() -> LossRleBuilder {
72 let mut builder = LossRleBuilder {
73 rle: Rle::builder(),
74 };
75 builder.rle = builder.rle.block_type(Self::BLOCK_TYPE);
76 builder
77 }
78}
79
80#[derive(Debug, Default)]
82pub struct LossRleBuilder {
83 rle: RleBuilder,
84}
85
86impl LossRleBuilder {
87 pub fn ssrc(mut self, ssrc: u32) -> Self {
89 self.rle = self.rle.ssrc(ssrc);
90 self
91 }
92
93 pub fn begin(mut self, begin: u16) -> Self {
95 self.rle = self.rle.begin(begin);
96 self
97 }
98
99 pub fn end(mut self, end: u16) -> Self {
101 self.rle = self.rle.end(end);
102 self
103 }
104
105 pub fn thinning(mut self, thinning: u8) -> Self {
109 assert!(thinning <= 0xf);
110 self.rle = self.rle.thinning(thinning);
111 self
112 }
113
114 pub fn add_chunk(mut self, chunk: RleChunk) -> Self {
116 self.rle = self.rle.add_chunk(chunk);
117 self
118 }
119}
120
121impl XrBlockBuilder<'_> for LossRleBuilder {
122 fn type_specific_byte(&self) -> u8 {
123 self.rle.type_specific_byte()
124 }
125}
126
127impl RtcpPacketWriter for LossRleBuilder {
128 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
129 self.rle.calculate_size()
130 }
131
132 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
133 self.rle.write_into_unchecked(buf)
134 }
135
136 fn get_padding(&self) -> Option<u8> {
137 None
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn loss_rle_builder_simple() {
147 let builder = LossRle::builder()
148 .ssrc(0x1357_9864)
149 .begin(400)
150 .end(500)
151 .thinning(1)
152 .add_chunk(RleChunk::RunLength(50));
153 let len = builder.calculate_size().unwrap();
154 let mut buf = vec![0; len];
155 builder.write_into_unchecked(&mut buf);
156 println!("{buf:x?}");
157
158 let rle = LossRle::parse(&buf).unwrap();
159 assert_eq!(rle.media_ssrc(), 0x1357_9864);
160 assert_eq!(rle.thinning(), 1);
161 assert_eq!(rle.begin(), 400);
162 assert_eq!(rle.end(), 500);
163 let expected = (400..500).filter(|x| x % 2 == 0).collect::<Vec<_>>();
164 let sequence = rle.sequence_iter().collect::<Vec<_>>();
165 assert_eq!(sequence, expected);
166 }
167}