1use std::borrow::Borrow;
4
5use crate::{
6 prelude::*,
7 utils::{pad_to_4bytes, parser, writer},
8 RtcpPacket, RtcpPacketParser, RtcpParseError, RtcpWriteError,
9};
10
11pub mod fir;
12pub mod nack;
13pub mod pli;
14pub mod rpsi;
15pub mod sli;
16
17#[derive(Debug, Default, PartialEq, Eq)]
20pub struct FciFeedbackPacketType {
21 transport: bool,
22 payload: bool,
23}
24
25impl FciFeedbackPacketType {
26 pub const NONE: Self = Self {
27 transport: false,
28 payload: false,
29 };
30 pub const TRANSPORT: Self = Self {
31 transport: true,
32 payload: false,
33 };
34 pub const PAYLOAD: Self = Self {
35 transport: false,
36 payload: true,
37 };
38}
39
40impl std::ops::BitOr<FciFeedbackPacketType> for FciFeedbackPacketType {
41 type Output = Self;
42 fn bitor(self, rhs: Self) -> Self::Output {
43 Self {
44 transport: self.transport | rhs.transport,
45 payload: self.payload | rhs.payload,
46 }
47 }
48}
49
50impl std::ops::BitAnd<FciFeedbackPacketType> for FciFeedbackPacketType {
51 type Output = Self;
52 fn bitand(self, rhs: Self) -> Self::Output {
53 Self {
54 transport: self.transport & rhs.transport,
55 payload: self.payload & rhs.payload,
56 }
57 }
58}
59
60#[derive(Clone, Debug, PartialEq, Eq)]
62pub struct TransportFeedback<'a> {
63 data: &'a [u8],
64}
65
66impl<'a> RtcpPacket for TransportFeedback<'a> {
67 const MIN_PACKET_LEN: usize = 12;
68 const PACKET_TYPE: u8 = 205;
69}
70
71impl<'a> RtcpPacketParser<'a> for TransportFeedback<'a> {
72 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
73 parser::check_packet::<Self>(data)?;
74 Ok(Self { data })
75 }
76
77 #[inline(always)]
78 fn header_data(&self) -> [u8; 4] {
79 self.data[..4].try_into().unwrap()
80 }
81}
82
83impl<'a> TransportFeedback<'a> {
84 pub fn builder(fci: &'a dyn FciBuilder<'a>) -> TransportFeedbackBuilder<'a> {
89 TransportFeedbackBuilder {
90 padding: 0,
91 sender_ssrc: 0,
92 media_ssrc: 0,
93 fci: FciBuilderWrapper::Borrowed(fci),
94 }
95 }
96
97 pub fn builder_owned(
104 fci: impl FciBuilder<'static> + 'static,
105 ) -> TransportFeedbackBuilder<'static> {
106 TransportFeedbackBuilder {
107 padding: 0,
108 sender_ssrc: 0,
109 media_ssrc: 0,
110 fci: FciBuilderWrapper::Owned(Box::new(fci)),
111 }
112 }
113
114 pub fn padding(&self) -> Option<u8> {
116 parser::parse_padding(self.data)
117 }
118
119 pub fn sender_ssrc(&self) -> u32 {
121 parser::parse_ssrc(self.data)
122 }
123
124 pub fn media_ssrc(&self) -> u32 {
126 parser::parse_ssrc(&self.data[4..])
127 }
128
129 pub fn parse_fci<F: FciParser<'a>>(&self) -> Result<F, RtcpParseError> {
136 if F::PACKET_TYPE & FciFeedbackPacketType::TRANSPORT == FciFeedbackPacketType::NONE {
137 return Err(RtcpParseError::WrongImplementation);
138 }
139 if parser::parse_count(self.data) != F::FCI_FORMAT {
140 return Err(RtcpParseError::WrongImplementation);
141 }
142 F::parse(&self.data[12..])
143 }
144}
145
146#[derive(Debug)]
148#[must_use = "The builder must be built to be used"]
149pub struct TransportFeedbackBuilder<'a> {
150 padding: u8,
151 sender_ssrc: u32,
152 media_ssrc: u32,
153 fci: FciBuilderWrapper<'a>,
154}
155
156impl<'a> TransportFeedbackBuilder<'a> {
157 pub fn sender_ssrc(mut self, sender_ssrc: u32) -> Self {
159 self.sender_ssrc = sender_ssrc;
160 self
161 }
162
163 pub fn media_ssrc(mut self, media_ssrc: u32) -> Self {
166 self.media_ssrc = media_ssrc;
167 self
168 }
169
170 pub fn padding(mut self, padding: u8) -> Self {
172 self.padding = padding;
173 self
174 }
175}
176
177#[inline]
178fn fb_write_into<T: RtcpPacket>(
179 feedback_type: FciFeedbackPacketType,
180 buf: &mut [u8],
181 sender_ssrc: u32,
182 media_ssrc: u32,
183 fci: &dyn FciBuilder,
184 padding: u8,
185) -> usize {
186 if feedback_type & fci.supports_feedback_type() == FciFeedbackPacketType::NONE {
187 return 0;
188 }
189
190 let fmt = fci.format();
191 assert!(fmt <= 0x1f);
192 let mut idx = writer::write_header_unchecked::<T>(padding, fmt, buf);
193
194 let mut end = idx;
195 end += 4;
196 buf[idx..end].copy_from_slice(&sender_ssrc.to_be_bytes());
197 idx = end;
198 end += 4;
199 buf[idx..end].copy_from_slice(&media_ssrc.to_be_bytes());
200 idx = end;
201
202 end += fci.write_into_unchecked(&mut buf[idx..]);
203
204 end += writer::write_padding_unchecked(padding, &mut buf[idx..]);
205
206 end
207}
208
209impl<'a> RtcpPacketWriter for TransportFeedbackBuilder<'a> {
210 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
217 writer::check_padding(self.padding)?;
218
219 if self.fci.supports_feedback_type() & FciFeedbackPacketType::TRANSPORT
220 == FciFeedbackPacketType::NONE
221 {
222 return Err(RtcpWriteError::FciWrongFeedbackPacketType);
223 }
224 let fci_len = self.fci.calculate_size()?;
225
226 Ok(TransportFeedback::MIN_PACKET_LEN + pad_to_4bytes(fci_len))
227 }
228
229 #[inline]
237 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
238 fb_write_into::<TransportFeedback>(
239 FciFeedbackPacketType::TRANSPORT,
240 buf,
241 self.sender_ssrc,
242 self.media_ssrc,
243 self.fci.as_ref(),
244 self.padding,
245 )
246 }
247
248 fn get_padding(&self) -> Option<u8> {
249 if self.padding == 0 {
250 return None;
251 }
252
253 Some(self.padding)
254 }
255}
256
257#[derive(Clone, Debug, PartialEq, Eq)]
259pub struct PayloadFeedback<'a> {
260 data: &'a [u8],
261}
262
263impl<'a> RtcpPacket for PayloadFeedback<'a> {
264 const MIN_PACKET_LEN: usize = 12;
265 const PACKET_TYPE: u8 = 206;
266}
267
268impl<'a> RtcpPacketParser<'a> for PayloadFeedback<'a> {
269 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
270 parser::check_packet::<Self>(data)?;
271 Ok(Self { data })
272 }
273
274 #[inline(always)]
275 fn header_data(&self) -> [u8; 4] {
276 self.data[..4].try_into().unwrap()
277 }
278}
279
280impl<'a> PayloadFeedback<'a> {
281 pub fn builder(fci: &'a dyn FciBuilder<'a>) -> PayloadFeedbackBuilder<'a> {
285 PayloadFeedbackBuilder {
286 padding: 0,
287 sender_ssrc: 0,
288 media_ssrc: 0,
289 fci: FciBuilderWrapper::Borrowed(fci),
290 }
291 }
292
293 pub fn builder_owned(
300 fci: impl FciBuilder<'static> + 'static,
301 ) -> PayloadFeedbackBuilder<'static> {
302 PayloadFeedbackBuilder {
303 padding: 0,
304 sender_ssrc: 0,
305 media_ssrc: 0,
306 fci: FciBuilderWrapper::Owned(Box::new(fci)),
307 }
308 }
309
310 pub fn padding(&self) -> Option<u8> {
312 parser::parse_padding(self.data)
313 }
314
315 pub fn sender_ssrc(&self) -> u32 {
317 parser::parse_ssrc(self.data)
318 }
319
320 pub fn media_ssrc(&self) -> u32 {
322 parser::parse_ssrc(&self.data[4..])
323 }
324
325 pub fn parse_fci<F: FciParser<'a>>(&self) -> Result<F, RtcpParseError> {
332 if F::PACKET_TYPE & FciFeedbackPacketType::PAYLOAD == FciFeedbackPacketType::NONE {
333 return Err(RtcpParseError::WrongImplementation);
334 }
335 if parser::parse_count(self.data) != F::FCI_FORMAT {
336 return Err(RtcpParseError::WrongImplementation);
337 }
338 F::parse(&self.data[12..])
339 }
340}
341
342#[derive(Debug)]
344#[must_use = "The builder must be built to be used"]
345pub struct PayloadFeedbackBuilder<'a> {
346 padding: u8,
347 sender_ssrc: u32,
348 media_ssrc: u32,
349 fci: FciBuilderWrapper<'a>,
350}
351
352impl<'a> PayloadFeedbackBuilder<'a> {
353 pub fn sender_ssrc(mut self, sender_ssrc: u32) -> Self {
355 self.sender_ssrc = sender_ssrc;
356 self
357 }
358
359 pub fn media_ssrc(mut self, media_ssrc: u32) -> Self {
362 self.media_ssrc = media_ssrc;
363 self
364 }
365
366 pub fn padding(mut self, padding: u8) -> Self {
368 self.padding = padding;
369 self
370 }
371}
372
373impl<'a> RtcpPacketWriter for PayloadFeedbackBuilder<'a> {
374 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
381 writer::check_padding(self.padding)?;
382
383 if self.fci.supports_feedback_type() & FciFeedbackPacketType::PAYLOAD
384 == FciFeedbackPacketType::NONE
385 {
386 return Err(RtcpWriteError::FciWrongFeedbackPacketType);
387 }
388 let fci_len = self.fci.calculate_size()?;
389
390 Ok(PayloadFeedback::MIN_PACKET_LEN + pad_to_4bytes(fci_len))
391 }
392
393 #[inline]
401 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
402 fb_write_into::<PayloadFeedback>(
403 FciFeedbackPacketType::PAYLOAD,
404 buf,
405 self.sender_ssrc,
406 self.media_ssrc,
407 self.fci.as_ref(),
408 self.padding,
409 )
410 }
411
412 fn get_padding(&self) -> Option<u8> {
413 if self.padding == 0 {
414 return None;
415 }
416
417 Some(self.padding)
418 }
419}
420
421pub trait FciParser<'a>: Sized {
423 const PACKET_TYPE: FciFeedbackPacketType;
424 const FCI_FORMAT: u8;
425
426 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
428}
429
430#[derive(Debug)]
441enum FciBuilderWrapper<'a> {
442 Borrowed(&'a dyn FciBuilder<'a>),
443 Owned(Box<dyn FciBuilder<'a>>),
448}
449
450impl<'a, T: FciBuilder<'a>> From<&'a T> for FciBuilderWrapper<'a> {
451 fn from(value: &'a T) -> Self {
452 FciBuilderWrapper::Borrowed(value)
453 }
454}
455
456impl<'a> std::convert::AsRef<dyn FciBuilder<'a> + 'a> for FciBuilderWrapper<'a> {
457 fn as_ref(&self) -> &(dyn FciBuilder<'a> + 'a) {
458 match self {
459 FciBuilderWrapper::Borrowed(this) => *this,
460 FciBuilderWrapper::Owned(this) => this.borrow(),
461 }
462 }
463}
464
465impl<'a> std::ops::Deref for FciBuilderWrapper<'a> {
466 type Target = dyn FciBuilder<'a> + 'a;
467
468 fn deref(&self) -> &(dyn FciBuilder<'a> + 'a) {
469 match self {
470 FciBuilderWrapper::Borrowed(this) => *this,
471 FciBuilderWrapper::Owned(this) => this.borrow(),
472 }
473 }
474}
475
476pub trait FciBuilder<'a>: RtcpPacketWriter {
479 fn format(&self) -> u8;
481 fn supports_feedback_type(&self) -> FciFeedbackPacketType;
483}