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 {
28 transport: false,
29 payload: false,
30 };
31 pub const TRANSPORT: Self = Self {
33 transport: true,
34 payload: false,
35 };
36 pub const PAYLOAD: Self = Self {
38 transport: false,
39 payload: true,
40 };
41}
42
43impl std::ops::BitOr<FciFeedbackPacketType> for FciFeedbackPacketType {
44 type Output = Self;
45 fn bitor(self, rhs: Self) -> Self::Output {
46 Self {
47 transport: self.transport | rhs.transport,
48 payload: self.payload | rhs.payload,
49 }
50 }
51}
52
53impl std::ops::BitAnd<FciFeedbackPacketType> for FciFeedbackPacketType {
54 type Output = Self;
55 fn bitand(self, rhs: Self) -> Self::Output {
56 Self {
57 transport: self.transport & rhs.transport,
58 payload: self.payload & rhs.payload,
59 }
60 }
61}
62
63#[derive(Clone, Debug, PartialEq, Eq)]
65pub struct TransportFeedback<'a> {
66 data: &'a [u8],
67}
68
69impl RtcpPacket for TransportFeedback<'_> {
70 const MIN_PACKET_LEN: usize = 12;
71 const PACKET_TYPE: u8 = 205;
72}
73
74impl<'a> RtcpPacketParser<'a> for TransportFeedback<'a> {
75 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
76 parser::check_packet::<Self>(data)?;
77 Ok(Self { data })
78 }
79
80 #[inline(always)]
81 fn header_data(&self) -> [u8; 4] {
82 self.data[..4].try_into().unwrap()
83 }
84}
85
86impl<'a> TransportFeedback<'a> {
87 pub fn builder(fci: &'a dyn FciBuilder<'a>) -> TransportFeedbackBuilder<'a> {
92 TransportFeedbackBuilder {
93 padding: 0,
94 sender_ssrc: 0,
95 media_ssrc: 0,
96 fci: FciBuilderWrapper::Borrowed(fci),
97 }
98 }
99
100 pub fn builder_owned(
107 fci: impl FciBuilder<'static> + 'static,
108 ) -> TransportFeedbackBuilder<'static> {
109 TransportFeedbackBuilder {
110 padding: 0,
111 sender_ssrc: 0,
112 media_ssrc: 0,
113 fci: FciBuilderWrapper::Owned(Box::new(fci)),
114 }
115 }
116
117 pub fn padding(&self) -> Option<u8> {
119 parser::parse_padding(self.data)
120 }
121
122 pub fn sender_ssrc(&self) -> u32 {
124 parser::parse_ssrc(self.data)
125 }
126
127 pub fn media_ssrc(&self) -> u32 {
129 parser::parse_ssrc(&self.data[4..])
130 }
131
132 pub fn parse_fci<F: FciParser<'a>>(&self) -> Result<F, RtcpParseError> {
139 if F::PACKET_TYPE & FciFeedbackPacketType::TRANSPORT == FciFeedbackPacketType::NONE {
140 return Err(RtcpParseError::WrongImplementation);
141 }
142 if parser::parse_count(self.data) != F::FCI_FORMAT {
143 return Err(RtcpParseError::WrongImplementation);
144 }
145 F::parse(&self.data[12..])
146 }
147}
148
149#[derive(Debug)]
151#[must_use = "The builder must be built to be used"]
152pub struct TransportFeedbackBuilder<'a> {
153 padding: u8,
154 sender_ssrc: u32,
155 media_ssrc: u32,
156 fci: FciBuilderWrapper<'a>,
157}
158
159impl TransportFeedbackBuilder<'_> {
160 pub fn sender_ssrc(mut self, sender_ssrc: u32) -> Self {
162 self.sender_ssrc = sender_ssrc;
163 self
164 }
165
166 pub fn media_ssrc(mut self, media_ssrc: u32) -> Self {
169 self.media_ssrc = media_ssrc;
170 self
171 }
172
173 pub fn padding(mut self, padding: u8) -> Self {
175 self.padding = padding;
176 self
177 }
178}
179
180#[inline]
181fn fb_write_into<T: RtcpPacket>(
182 feedback_type: FciFeedbackPacketType,
183 buf: &mut [u8],
184 sender_ssrc: u32,
185 media_ssrc: u32,
186 fci: &dyn FciBuilder,
187 padding: u8,
188) -> usize {
189 if feedback_type & fci.supports_feedback_type() == FciFeedbackPacketType::NONE {
190 return 0;
191 }
192
193 let fmt = fci.format();
194 assert!(fmt <= 0x1f);
195 let mut idx = writer::write_header_unchecked::<T>(padding, fmt, buf);
196
197 let mut end = idx;
198 end += 4;
199 buf[idx..end].copy_from_slice(&sender_ssrc.to_be_bytes());
200 idx = end;
201 end += 4;
202 buf[idx..end].copy_from_slice(&media_ssrc.to_be_bytes());
203 idx = end;
204
205 end += fci.write_into_unchecked(&mut buf[idx..]);
206
207 end += writer::write_padding_unchecked(padding, &mut buf[idx..]);
208
209 end
210}
211
212impl RtcpPacketWriter for TransportFeedbackBuilder<'_> {
213 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
220 writer::check_padding(self.padding)?;
221
222 if self.fci.supports_feedback_type() & FciFeedbackPacketType::TRANSPORT
223 == FciFeedbackPacketType::NONE
224 {
225 return Err(RtcpWriteError::FciWrongFeedbackPacketType);
226 }
227 let fci_len = self.fci.calculate_size()?;
228
229 Ok(TransportFeedback::MIN_PACKET_LEN + pad_to_4bytes(fci_len))
230 }
231
232 #[inline]
240 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
241 fb_write_into::<TransportFeedback>(
242 FciFeedbackPacketType::TRANSPORT,
243 buf,
244 self.sender_ssrc,
245 self.media_ssrc,
246 self.fci.as_ref(),
247 self.padding,
248 )
249 }
250
251 fn get_padding(&self) -> Option<u8> {
252 if self.padding == 0 {
253 return None;
254 }
255
256 Some(self.padding)
257 }
258}
259
260#[derive(Clone, Debug, PartialEq, Eq)]
262pub struct PayloadFeedback<'a> {
263 data: &'a [u8],
264}
265
266impl RtcpPacket for PayloadFeedback<'_> {
267 const MIN_PACKET_LEN: usize = 12;
268 const PACKET_TYPE: u8 = 206;
269}
270
271impl<'a> RtcpPacketParser<'a> for PayloadFeedback<'a> {
272 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
273 parser::check_packet::<Self>(data)?;
274 Ok(Self { data })
275 }
276
277 #[inline(always)]
278 fn header_data(&self) -> [u8; 4] {
279 self.data[..4].try_into().unwrap()
280 }
281}
282
283impl<'a> PayloadFeedback<'a> {
284 pub fn builder(fci: &'a dyn FciBuilder<'a>) -> PayloadFeedbackBuilder<'a> {
288 PayloadFeedbackBuilder {
289 padding: 0,
290 sender_ssrc: 0,
291 media_ssrc: 0,
292 fci: FciBuilderWrapper::Borrowed(fci),
293 }
294 }
295
296 pub fn builder_owned(
303 fci: impl FciBuilder<'static> + 'static,
304 ) -> PayloadFeedbackBuilder<'static> {
305 PayloadFeedbackBuilder {
306 padding: 0,
307 sender_ssrc: 0,
308 media_ssrc: 0,
309 fci: FciBuilderWrapper::Owned(Box::new(fci)),
310 }
311 }
312
313 pub fn padding(&self) -> Option<u8> {
315 parser::parse_padding(self.data)
316 }
317
318 pub fn sender_ssrc(&self) -> u32 {
320 parser::parse_ssrc(self.data)
321 }
322
323 pub fn media_ssrc(&self) -> u32 {
325 parser::parse_ssrc(&self.data[4..])
326 }
327
328 pub fn parse_fci<F: FciParser<'a>>(&self) -> Result<F, RtcpParseError> {
335 if F::PACKET_TYPE & FciFeedbackPacketType::PAYLOAD == FciFeedbackPacketType::NONE {
336 return Err(RtcpParseError::WrongImplementation);
337 }
338 if parser::parse_count(self.data) != F::FCI_FORMAT {
339 return Err(RtcpParseError::WrongImplementation);
340 }
341 F::parse(&self.data[12..])
342 }
343}
344
345#[derive(Debug)]
347#[must_use = "The builder must be built to be used"]
348pub struct PayloadFeedbackBuilder<'a> {
349 padding: u8,
350 sender_ssrc: u32,
351 media_ssrc: u32,
352 fci: FciBuilderWrapper<'a>,
353}
354
355impl PayloadFeedbackBuilder<'_> {
356 pub fn sender_ssrc(mut self, sender_ssrc: u32) -> Self {
358 self.sender_ssrc = sender_ssrc;
359 self
360 }
361
362 pub fn media_ssrc(mut self, media_ssrc: u32) -> Self {
365 self.media_ssrc = media_ssrc;
366 self
367 }
368
369 pub fn padding(mut self, padding: u8) -> Self {
371 self.padding = padding;
372 self
373 }
374}
375
376impl RtcpPacketWriter for PayloadFeedbackBuilder<'_> {
377 fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
384 writer::check_padding(self.padding)?;
385
386 if self.fci.supports_feedback_type() & FciFeedbackPacketType::PAYLOAD
387 == FciFeedbackPacketType::NONE
388 {
389 return Err(RtcpWriteError::FciWrongFeedbackPacketType);
390 }
391 let fci_len = self.fci.calculate_size()?;
392
393 Ok(PayloadFeedback::MIN_PACKET_LEN + pad_to_4bytes(fci_len))
394 }
395
396 #[inline]
404 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
405 fb_write_into::<PayloadFeedback>(
406 FciFeedbackPacketType::PAYLOAD,
407 buf,
408 self.sender_ssrc,
409 self.media_ssrc,
410 self.fci.as_ref(),
411 self.padding,
412 )
413 }
414
415 fn get_padding(&self) -> Option<u8> {
416 if self.padding == 0 {
417 return None;
418 }
419
420 Some(self.padding)
421 }
422}
423
424pub trait FciParser<'a>: Sized {
426 const PACKET_TYPE: FciFeedbackPacketType;
428 const FCI_FORMAT: u8;
430
431 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
433}
434
435#[derive(Debug)]
446enum FciBuilderWrapper<'a> {
447 Borrowed(&'a dyn FciBuilder<'a>),
448 Owned(Box<dyn FciBuilder<'a>>),
453}
454
455impl<'a, T: FciBuilder<'a>> From<&'a T> for FciBuilderWrapper<'a> {
456 fn from(value: &'a T) -> Self {
457 FciBuilderWrapper::Borrowed(value)
458 }
459}
460
461impl<'a> std::convert::AsRef<dyn FciBuilder<'a> + 'a> for FciBuilderWrapper<'a> {
462 fn as_ref(&self) -> &(dyn FciBuilder<'a> + 'a) {
463 match self {
464 FciBuilderWrapper::Borrowed(this) => *this,
465 FciBuilderWrapper::Owned(this) => this.borrow(),
466 }
467 }
468}
469
470impl<'a> std::ops::Deref for FciBuilderWrapper<'a> {
471 type Target = dyn FciBuilder<'a> + 'a;
472
473 fn deref(&self) -> &(dyn FciBuilder<'a> + 'a) {
474 match self {
475 FciBuilderWrapper::Borrowed(this) => *this,
476 FciBuilderWrapper::Owned(this) => this.borrow(),
477 }
478 }
479}
480
481pub trait FciBuilder<'a>: RtcpPacketWriter {
484 fn format(&self) -> u8;
486 fn supports_feedback_type(&self) -> FciFeedbackPacketType;
488}