1use crate::{
4 prelude::*,
5 utils::{parser, writer},
6 ReportBlock, ReportBlockBuilder, RtcpPacket, RtcpParseError, RtcpWriteError,
7};
8
9#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct ReceiverReport<'a> {
12 data: &'a [u8],
13}
14
15impl RtcpPacket for ReceiverReport<'_> {
16 const MIN_PACKET_LEN: usize = 8;
17 const PACKET_TYPE: u8 = 201;
18}
19
20impl<'a> RtcpPacketParser<'a> for ReceiverReport<'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> ReceiverReport<'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 report_blocks(&self) -> impl Iterator<Item = ReportBlock<'a>> + '_ {
62 self.data[Self::MIN_PACKET_LEN..Self::MIN_PACKET_LEN + (self.n_reports() as usize * 24)]
63 .chunks_exact(24)
64 .map(|b| ReportBlock::parse(b).unwrap())
65 }
66
67 pub fn builder(ssrc: u32) -> ReceiverReportBuilder {
69 ReceiverReportBuilder::new(ssrc)
70 }
71}
72
73#[derive(Debug)]
75#[must_use = "The builder must be built to be used"]
76pub struct ReceiverReportBuilder {
77 ssrc: u32,
78 padding: u8,
79 report_blocks: Vec<ReportBlockBuilder>,
80}
81
82impl ReceiverReportBuilder {
83 fn new(ssrc: u32) -> Self {
84 ReceiverReportBuilder {
85 ssrc,
86 padding: 0,
87 report_blocks: Vec::with_capacity(ReceiverReport::MAX_REPORTS as usize),
88 }
89 }
90
91 pub fn padding(mut self, padding: u8) -> Self {
93 self.padding = padding;
94 self
95 }
96
97 pub fn add_report_block(mut self, report_block: ReportBlockBuilder) -> Self {
99 self.report_blocks.push(report_block);
100 self
101 }
102}
103
104impl RtcpPacketWriter for ReceiverReportBuilder {
105 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
113 if self.report_blocks.len() > ReceiverReport::MAX_REPORTS as usize {
114 return Err(RtcpWriteError::TooManyReportBlocks {
115 count: self.report_blocks.len(),
116 max: ReceiverReport::MAX_REPORTS,
117 });
118 }
119
120 writer::check_padding(self.padding)?;
121
122 let mut report_blocks_size = 0;
123 for rb in self.report_blocks.iter() {
124 report_blocks_size += rb.calculate_size()?;
125 }
126
127 Ok(ReceiverReport::MIN_PACKET_LEN + report_blocks_size + self.padding as usize)
128 }
129
130 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
140 writer::write_header_unchecked::<ReceiverReport>(
141 self.padding,
142 self.report_blocks.len() as u8,
143 buf,
144 );
145
146 buf[4..8].copy_from_slice(&self.ssrc.to_be_bytes());
147
148 let mut idx = 8;
149 let mut end = idx;
150 for report_block in self.report_blocks.iter() {
151 end += ReportBlock::EXPECTED_SIZE;
152 report_block.write_into_unchecked(&mut buf[idx..end]);
153 idx = end;
154 }
155
156 end += writer::write_padding_unchecked(self.padding, &mut buf[idx..]);
157
158 end
159 }
160
161 fn get_padding(&self) -> Option<u8> {
162 if self.padding == 0 {
163 return None;
164 }
165
166 Some(self.padding)
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173
174 #[test]
175 fn parse_empty_rr() {
176 let data = [0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64];
177 let rr = ReceiverReport::parse(&data).unwrap();
178 assert_eq!(rr.version(), 2);
179 assert_eq!(rr.padding(), None);
180 assert_eq!(rr.n_reports(), 0);
181 assert_eq!(rr.report_blocks().count(), 0);
182 }
183
184 #[test]
185 fn build_empty_rr() {
186 const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN;
187 let rrb = ReceiverReport::builder(0x91827364);
188 let req_len = rrb.calculate_size().unwrap();
189 assert_eq!(req_len, REQ_LEN);
190
191 let mut data = [0; REQ_LEN];
192 let len = rrb.write_into(&mut data).unwrap();
193 assert_eq!(len, REQ_LEN);
194 assert_eq!(data, [0x80, 0xc9, 0x00, 0x01, 0x91, 0x82, 0x73, 0x64]);
195 }
196
197 #[test]
198 fn build_2_blocks_rr() {
199 let rb1 = ReportBlock::builder(0x1234567);
200 let rb2 = ReportBlock::builder(0x1234568);
201
202 const REQ_LEN: usize = ReceiverReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2;
203 let rrb = ReceiverReport::builder(0x91827364)
204 .add_report_block(rb1)
205 .add_report_block(rb2);
206 let req_len = rrb.calculate_size().unwrap();
207 assert_eq!(req_len, REQ_LEN);
208
209 let mut data = [0; REQ_LEN];
210 let len = rrb.write_into(&mut data).unwrap();
211 assert_eq!(len, REQ_LEN);
212 assert_eq!(
213 data,
214 [
215 0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219 ]
220 );
221 }
222
223 #[test]
224 fn build_2_blocks_padded_rr() {
225 let rb1 = ReportBlock::builder(0x1234567);
226 let rb2 = ReportBlock::builder(0x1234568);
227
228 const PADDING: usize = 4;
229 const REQ_LEN: usize =
230 ReceiverReport::MIN_PACKET_LEN + ReportBlock::EXPECTED_SIZE * 2 + PADDING;
231 let rrb = ReceiverReport::builder(0x91827364)
232 .padding(PADDING as u8)
233 .add_report_block(rb1)
234 .add_report_block(rb2);
235 let req_len = rrb.calculate_size().unwrap();
236 assert_eq!(req_len, REQ_LEN);
237
238 let mut data = [0; REQ_LEN];
239 let len = rrb.write_into(&mut data).unwrap();
240 assert_eq!(len, REQ_LEN);
241 assert_eq!(
242 data,
243 [
244 0xa2, 0xc9, 0x00, 0x0e, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248 0x00, 0x00, 0x00, 0x04,
249 ]
250 );
251 }
252
253 #[test]
254 fn parse_rr_with_2_rb() {
255 let rr = ReceiverReport::parse(&[
256 0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x00, 0x01, 0x23, 0x45, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
260 ])
261 .unwrap();
262 assert_eq!(rr.version(), 2);
263 assert_eq!(rr.padding(), None);
264 assert_eq!(rr.n_reports(), 2);
265 assert_eq!(rr.length(), 56);
266 assert_eq!(rr.ssrc(), 0x91827364);
267 let mut rb = rr.report_blocks();
268 let rb_item = rb.next().unwrap();
269 assert_eq!(rb_item.ssrc(), 0x01234567);
270 let rb_item = rb.next().unwrap();
271 assert_eq!(rb_item.ssrc(), 0x01234568);
272 assert_eq!(rb.next(), None);
273 }
274
275 #[test]
276 fn parse_rr_short() {
277 assert_eq!(
278 ReceiverReport::parse(&[0]),
279 Err(RtcpParseError::Truncated {
280 expected: 8,
281 actual: 1
282 })
283 );
284 }
285
286 #[test]
287 fn parse_sr_too_short_for_report_count() {
288 assert_eq!(
289 ReceiverReport::parse(&[
290 0x82, 0xc9, 0x00, 0x0d, 0x91, 0x82, 0x73, 0x64, 0x01, 0x23, 0x45, 0x67, 0x00, 0x00,
291 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292 0x00, 0x00, 0x00, 0x00,
293 ]),
294 Err(RtcpParseError::Truncated {
295 expected: 56,
296 actual: 32
297 })
298 );
299 }
300
301 #[test]
302 fn build_too_many_report_blocks() {
303 let mut b = ReceiverReport::builder(0);
304 for _ in 0..ReceiverReport::MAX_REPORTS as usize + 1 {
305 b = b.add_report_block(ReportBlock::builder(1));
306 }
307 let err = b.calculate_size().unwrap_err();
308 assert_eq!(
309 err,
310 RtcpWriteError::TooManyReportBlocks {
311 count: ReceiverReport::MAX_REPORTS as usize + 1,
312 max: ReceiverReport::MAX_REPORTS
313 }
314 );
315 }
316
317 #[test]
318 fn build_erroneous_report() {
319 let b = ReceiverReport::builder(0)
320 .add_report_block(ReportBlock::builder(1).cumulative_lost(0xffffff + 1));
321 let err = b.calculate_size().unwrap_err();
322 assert_eq!(
323 err,
324 RtcpWriteError::CumulativeLostTooLarge {
325 value: 0xffffff + 1,
326 max: 0xffffff,
327 }
328 );
329 }
330
331 #[test]
332 fn build_padding_not_multiple_4() {
333 let b = ReceiverReport::builder(0).padding(5);
334 let err = b.calculate_size().unwrap_err();
335 assert_eq!(err, RtcpWriteError::InvalidPadding { padding: 5 });
336 }
337}