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