1#![deny(missing_debug_implementations)]
4#![deny(missing_docs)]
5
6pub trait RtcpPacket {
14 const VERSION: u8 = 2;
17 const MAX_COUNT: u8 = 0x1f;
20 const MIN_PACKET_LEN: usize;
23 const PACKET_TYPE: u8;
25}
26
27pub trait RtcpPacketParser<'a>: RtcpPacket + Sized {
33 fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
38
39 fn header_data(&self) -> [u8; 4];
41}
42
43pub trait RtcpPacketParserExt<'a>: RtcpPacketParser<'a> {
46 fn version(&self) -> u8 {
48 utils::parser::parse_version(&self.header_data())
49 }
50
51 fn type_(&self) -> u8 {
53 utils::parser::parse_packet_type(&self.header_data())
54 }
55
56 fn subtype(&self) -> u8 {
58 utils::parser::parse_count(&self.header_data())
59 }
60
61 fn length(&self) -> usize {
63 utils::parser::parse_length(&self.header_data())
64 }
65
66 fn count(&self) -> u8 {
68 utils::parser::parse_count(&self.header_data())
69 }
70}
71
72impl<'a, T: RtcpPacketParser<'a>> RtcpPacketParserExt<'a> for T {}
73
74pub trait RtcpPacketWriter: std::fmt::Debug + Send + Sync {
80 fn calculate_size(&self) -> Result<usize, RtcpWriteError>;
84
85 fn write_into_unchecked(&self, buf: &mut [u8]) -> usize;
95
96 fn get_padding(&self) -> Option<u8>;
98}
99
100pub trait RtcpPacketWriterExt: RtcpPacketWriter {
102 fn write_into(&self, buf: &mut [u8]) -> Result<usize, RtcpWriteError> {
110 let req_size = self.calculate_size()?;
111 if buf.len() < req_size {
112 return Err(RtcpWriteError::OutputTooSmall(req_size));
113 }
114
115 Ok(self.write_into_unchecked(&mut buf[..req_size]))
116 }
117}
118
119impl<T: RtcpPacketWriter> RtcpPacketWriterExt for T {}
120
121#[derive(thiserror::Error, Debug, PartialEq, Eq)]
123#[non_exhaustive]
124pub enum RtcpParseError {
125 #[error("Unsupported version: {}. This implementation only deals with version 2.", .0)]
127 UnsupportedVersion(u8),
128 #[error("The packet was too short to parse. Expected size: {expected}, actual size encountered: {actual}")]
130 Truncated {
131 expected: usize,
133 actual: usize,
135 },
136 #[error("The packet was too large to parse. Expected size: {expected}, actual size encountered: {actual}")]
138 TooLarge {
139 expected: usize,
141 actual: usize,
143 },
144 #[error("Invalid Padding length 0")]
146 InvalidPadding,
147
148 #[error("The SDES Value length {len} was too large (max {max})")]
150 SdesValueTooLarge {
151 len: usize,
153 max: u8,
155 },
156
157 #[error("The SDES PRIC content length {len} was too short (min {min})")]
159 SdesPrivContentTruncated {
160 len: usize,
162 min: u8,
164 },
165
166 #[error("The SDES PRIV prefix length {len} too large (available {available})")]
168 SdesPrivPrefixTooLarge {
169 len: usize,
171 available: u8,
173 },
174
175 #[error("This implementation does not handle this packet")]
177 WrongImplementation,
178
179 #[error("RTCP Packet type mismatch. Actual: {actual}, requested {requested}")]
181 PacketTypeMismatch {
182 actual: u8,
184 requested: u8,
186 },
187
188 #[error("The TWCC packet contains fewer delta bytes than required by the packet status list")]
190 TwccDeltaTruncated,
191
192 #[error("The TWCC packet contains reserved status bits")]
194 TwccReservedPacketStatus,
195}
196
197#[derive(thiserror::Error, Debug, PartialEq, Eq)]
199#[non_exhaustive]
200pub enum RtcpWriteError {
201 #[error("Output buffer is not large enough to fit the resulting buffer. Requested size: {}", .0)]
204 OutputTooSmall(usize),
205
206 #[error("The provided padding {padding} is not a multiple of 4")]
208 InvalidPadding {
209 padding: u8,
211 },
212
213 #[error("App Subtype {subtype} was out of range (max: {max})")]
215 AppSubtypeOutOfRange {
216 subtype: u8,
218 max: u8,
220 },
221
222 #[error("APP Packet Name is invalid. Expecting a sequence of four ASCII characters.")]
224 InvalidName,
225
226 #[error("Data length must be a mutliple of 32bits. Data len: {}", .0)]
228 DataLen32bitMultiple(usize),
229
230 #[error("Too many Sources specified. Number of Sources: {count}, max: {max}")]
232 TooManySources {
233 count: usize,
235 max: u8,
237 },
238
239 #[error("Reason length {len} was too large (max {max})")]
241 ReasonLenTooLarge {
242 len: usize,
244 max: u8,
246 },
247
248 #[error("Cumulative Lost {value} was too large (max {max})")]
250 CumulativeLostTooLarge {
251 value: u32,
253 max: u32,
255 },
256
257 #[error("Too many Report Blocks specified. Number of Report Blocks: {count} max: {max}")]
259 TooManyReportBlocks {
260 count: usize,
262 max: u8,
264 },
265
266 #[error("Too many SDES Chunks specified. Number of SDES Chunks: {count}, max: {max}")]
268 TooManySdesChunks {
269 count: usize,
271 max: u8,
273 },
274
275 #[error("SDES Value length {len} was too large (max {max})")]
277 SdesValueTooLarge {
278 len: usize,
280 max: u8,
282 },
283
284 #[error("The SDES PRIV prefix length {len} too large (max {max})")]
286 SdesPrivPrefixTooLarge {
287 len: usize,
289 max: u8,
291 },
292
293 #[error("Unknown Count {count} was out of range (max: {max})")]
295 CountOutOfRange {
296 count: u8,
298 max: u8,
300 },
301
302 #[error("Non-last Compound packet padding defined")]
304 NonLastCompoundPacketPadding,
305
306 #[error("Feedback packet does not contain any FCI data")]
308 MissingFci,
309
310 #[error("The number of NACK entries will not fit inside a RTCP packet.")]
312 TooManyNack,
313
314 #[error("Wrong feedback packet type for the provided FCI data")]
316 FciWrongFeedbackPacketType,
317
318 #[error("The RTP payload value is not a valid value")]
320 PayloadTypeInvalid,
321
322 #[error("The amount of padding bits are greater than the size of the data")]
324 PaddingBitsTooLarge,
325
326 #[error("The number of FIR entries will not fit inside a RTCP packet.")]
328 TooManyFir,
329
330 #[error("The TWCC reference time is too large.")]
332 TwccReferenceTimeTooLarge,
333}
334
335impl From<RtcpParseError> for RtcpWriteError {
336 fn from(err: RtcpParseError) -> Self {
337 match err {
338 RtcpParseError::SdesValueTooLarge { len, max } => {
339 RtcpWriteError::SdesValueTooLarge { len, max }
340 }
341 RtcpParseError::SdesPrivPrefixTooLarge { len, available } => {
342 RtcpWriteError::SdesPrivPrefixTooLarge {
343 len,
344 max: available,
345 }
346 }
347 other => unreachable!("{}", other),
348 }
349 }
350}
351
352mod app;
353mod bye;
354mod compound;
355mod feedback;
356mod receiver;
357mod report_block;
358mod sdes;
359mod sender;
360pub mod utils;
361mod xr;
362
363pub use app::{App, AppBuilder};
364pub use bye::{Bye, ByeBuilder};
365pub use compound::{Compound, CompoundBuilder, Packet, PacketBuilder, Unknown, UnknownBuilder};
366pub use feedback::fir::{Fir, FirBuilder, FirEntry};
367pub use feedback::nack::{Nack, NackBuilder};
368pub use feedback::pli::{Pli, PliBuilder};
369pub use feedback::rpsi::{Rpsi, RpsiBuilder};
370pub use feedback::sli::{Sli, SliBuilder};
371pub use feedback::twcc::{Twcc, TwccBuilder, TwccPacketStatus, TWCC_MAX_REFERENCE_TIME};
372pub use feedback::{
373 FciBuilder, FciFeedbackPacketType, FciParser, PayloadFeedback, PayloadFeedbackBuilder,
374 TransportFeedback, TransportFeedbackBuilder,
375};
376pub use receiver::{ReceiverReport, ReceiverReportBuilder};
377pub use report_block::{ReportBlock, ReportBlockBuilder};
378pub use sdes::{Sdes, SdesBuilder, SdesChunk, SdesChunkBuilder, SdesItem, SdesItemBuilder};
379pub use sender::{SenderReport, SenderReportBuilder};
380pub use xr::dlrr::{
381 DelaySinceLastReceiverReport, DelaySinceLastReceiverReportBlock,
382 DelaySinceLastReceiverReportBlockBuilder, DelaySinceLastReceiverReportBuilder,
383};
384pub use xr::duplicate_rle::{DuplicateRle, DuplicateRleBuilder};
385pub use xr::loss_rle::{LossRle, LossRleBuilder};
386pub use xr::packet_receipt_time::{PacketReceiptTimes, PacketReceiptTimesBuilder};
387pub use xr::receiver_reference_time::{ReceiverReferenceTime, ReceiverReferenceTimeBuilder};
388pub use xr::rle::RleChunk;
389pub use xr::{
390 Xr, XrBlock, XrBlockBuilder, XrBlockBuilderExt, XrBlockParser, XrBlockParserExt,
391 XrBlockStaticType, XrBuilder,
392};
393
394pub mod prelude {
396 pub use super::{
397 FciBuilder, FciParser, RtcpPacket, RtcpPacketParser, RtcpPacketParserExt, RtcpPacketWriter,
398 RtcpPacketWriterExt, XrBlockBuilder, XrBlockBuilderExt, XrBlockParser, XrBlockParserExt,
399 XrBlockStaticType,
400 };
401}