1use crate::{utils::u32_from_be_bytes, RtcpParseError, RtcpWriteError};
4
5#[derive(Debug, PartialEq, Eq)]
8pub struct ReportBlock<'a> {
9 data: &'a [u8; ReportBlock::EXPECTED_SIZE],
10}
11
12impl<'a> ReportBlock<'a> {
13 pub const EXPECTED_SIZE: usize = 24;
16
17 pub fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
19 if data.len() < Self::EXPECTED_SIZE {
20 return Err(RtcpParseError::Truncated {
21 expected: Self::EXPECTED_SIZE,
22 actual: data.len(),
23 });
24 }
25 if data.len() > Self::EXPECTED_SIZE {
26 return Err(RtcpParseError::TooLarge {
27 expected: Self::EXPECTED_SIZE,
28 actual: data.len(),
29 });
30 }
31 Ok(Self {
32 data: data.try_into().unwrap(),
33 })
34 }
35
36 pub fn ssrc(&self) -> u32 {
38 u32_from_be_bytes(&self.data[0..4])
39 }
40
41 pub fn fraction_lost(&self) -> u8 {
43 self.data[4]
44 }
45
46 pub fn cumulative_lost(&self) -> u32 {
48 u32_from_be_bytes(&self.data[4..8]) & 0xffffff
49 }
50
51 pub fn extended_sequence_number(&self) -> u32 {
53 u32_from_be_bytes(&self.data[8..12])
54 }
55
56 pub fn interarrival_jitter(&self) -> u32 {
58 u32_from_be_bytes(&self.data[12..16])
59 }
60
61 pub fn last_sender_report_timestamp(&self) -> u32 {
63 u32_from_be_bytes(&self.data[16..20])
64 }
65
66 pub fn delay_since_last_sender_report_timestamp(&self) -> u32 {
68 u32_from_be_bytes(&self.data[20..24])
69 }
70
71 pub fn builder(ssrc: u32) -> ReportBlockBuilder {
73 ReportBlockBuilder::new(ssrc)
74 }
75}
76
77#[derive(Debug, Eq, PartialEq)]
79#[must_use = "The builder must be built to be used"]
80pub struct ReportBlockBuilder {
81 ssrc: u32,
82 fraction_lost: u8,
83 cumulative_lost: u32,
84 extended_sequence_number: u32,
85 interarrival_jitter: u32,
86 last_sender_report_timestamp: u32,
87 delay_since_last_sender_report_timestamp: u32,
88}
89
90impl ReportBlockBuilder {
91 fn new(ssrc: u32) -> Self {
92 ReportBlockBuilder {
93 ssrc,
94 fraction_lost: 0,
95 cumulative_lost: 0,
96 extended_sequence_number: 0,
97 interarrival_jitter: 0,
98 last_sender_report_timestamp: 0,
99 delay_since_last_sender_report_timestamp: 0,
100 }
101 }
102
103 pub fn fraction_lost(mut self, fraction_lost: u8) -> Self {
105 self.fraction_lost = fraction_lost;
106 self
107 }
108
109 pub fn cumulative_lost(mut self, cumulative_lost: u32) -> Self {
111 self.cumulative_lost = cumulative_lost;
112 self
113 }
114
115 pub fn extended_sequence_number(mut self, extended_sequence_number: u32) -> Self {
117 self.extended_sequence_number = extended_sequence_number;
118 self
119 }
120
121 pub fn interarrival_jitter(mut self, interarrival_jitter: u32) -> Self {
123 self.interarrival_jitter = interarrival_jitter;
124 self
125 }
126
127 pub fn last_sender_report_timestamp(mut self, last_sender_report_timestamp: u32) -> Self {
129 self.last_sender_report_timestamp = last_sender_report_timestamp;
130 self
131 }
132
133 pub fn delay_since_last_sender_report_timestamp(
135 mut self,
136 delay_since_last_sender_report_timestamp: u32,
137 ) -> Self {
138 self.delay_since_last_sender_report_timestamp = delay_since_last_sender_report_timestamp;
139 self
140 }
141
142 pub(crate) fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
148 if self.cumulative_lost & !0xffffff != 0 {
149 return Err(RtcpWriteError::CumulativeLostTooLarge {
150 value: self.cumulative_lost,
151 max: 0xffffff,
152 });
153 }
154
155 Ok(ReportBlock::EXPECTED_SIZE)
156 }
157
158 #[inline]
166 pub(crate) fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
167 buf[0..4].copy_from_slice(&self.ssrc.to_be_bytes());
168 buf[4..8].copy_from_slice(&self.cumulative_lost.to_be_bytes());
169 buf[4] = self.fraction_lost;
170 buf[8..12].copy_from_slice(&self.extended_sequence_number.to_be_bytes());
171 buf[12..16].copy_from_slice(&self.interarrival_jitter.to_be_bytes());
172 buf[16..20].copy_from_slice(&self.last_sender_report_timestamp.to_be_bytes());
173 buf[20..].copy_from_slice(&self.delay_since_last_sender_report_timestamp.to_be_bytes());
174
175 ReportBlock::EXPECTED_SIZE
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn parse_report_block() {
185 let data = [
186 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, 0x8a, 0xac,
187 0xce, 0xe0, 0xf1, 0xd3, 0xb5, 0x97, 0x79, 0x5b, 0x3d, 0x1f,
188 ];
189 let rb = ReportBlock::parse(&data).unwrap();
190 assert_eq!(rb.ssrc(), 0x1234567);
191 assert_eq!(rb.fraction_lost(), 0x89);
192 assert_eq!(rb.cumulative_lost(), 0xabcdef);
193 assert_eq!(rb.extended_sequence_number(), 0x02244668);
194 assert_eq!(rb.interarrival_jitter(), 0x8aaccee0);
195 assert_eq!(rb.last_sender_report_timestamp(), 0xf1d3b597);
196 assert_eq!(rb.delay_since_last_sender_report_timestamp(), 0x795b3d1f);
197 }
198
199 #[test]
200 fn build_report_block() {
201 let rbb = ReportBlock::builder(0x1234567)
202 .fraction_lost(0x89)
203 .cumulative_lost(0xabcdef)
204 .extended_sequence_number(0x02244668)
205 .interarrival_jitter(0x8aaccee0)
206 .last_sender_report_timestamp(0xf1d3b597)
207 .delay_since_last_sender_report_timestamp(0x795b3d1f);
208 let req_size = rbb.calculate_size().unwrap();
209 assert_eq!(req_size, ReportBlock::EXPECTED_SIZE);
210
211 let mut buf = [0; ReportBlock::EXPECTED_SIZE];
212 let len = rbb.write_into_unchecked(&mut buf);
213 assert_eq!(len, ReportBlock::EXPECTED_SIZE);
214 assert_eq!(
215 buf,
216 [
217 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x02, 0x24, 0x46, 0x68, 0x8a, 0xac,
218 0xce, 0xe0, 0xf1, 0xd3, 0xb5, 0x97, 0x79, 0x5b, 0x3d, 0x1f,
219 ]
220 );
221 }
222
223 #[test]
224 fn short_report_block() {
225 assert_eq!(
226 ReportBlock::parse(&[0]),
227 Err(RtcpParseError::Truncated {
228 expected: 24,
229 actual: 1
230 })
231 );
232 }
233
234 #[test]
235 fn too_large_report_block() {
236 let data = [0; 25];
237 assert_eq!(
238 ReportBlock::parse(&data),
239 Err(RtcpParseError::TooLarge {
240 expected: 24,
241 actual: 25
242 })
243 );
244 }
245}