rtcp_types/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3#![deny(missing_debug_implementations)]
4#![deny(missing_docs)]
5
6//! # rtcp-type
7//!
8//! A crate for parsing and writing RTCP packets as specified in [RFC 3550] and related extensions.
9//!
10//! [RFC 3550]: https://tools.ietf.org/html/rfc3550
11
12/// A Trait defining RTCP Packet structural data.
13pub trait RtcpPacket {
14    /// RTCP protocol version.  The default version of 2 is fine and should not need to be
15    /// overriden.
16    const VERSION: u8 = 2;
17    /// A maximum count that is commonly used across multiple RTCP packet types.  A value larger
18    /// than this will produce a parsing error.
19    const MAX_COUNT: u8 = 0x1f;
20    /// The minimum size of a particular RTCP packet.  A packet shorter than this value will
21    /// produce a parsing error.
22    const MIN_PACKET_LEN: usize;
23    /// The RTCP type of the particular RTCP packet.
24    const PACKET_TYPE: u8;
25}
26
27/// A Trait to ease the implementation of RTCP Packet parsers.
28///
29/// Implementers only need to return the 4 byte RTCP header
30/// from [`RtcpPacketParser::header_data`] to be able to use
31/// the getters for the common RTCP packet fields.
32pub trait RtcpPacketParser<'a>: RtcpPacket + Sized {
33    /// Parses the provided data.
34    ///
35    /// Returns an instance of `Self` if parsing succeeds,
36    /// an `RtcpParseError` otherwise.
37    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
38
39    /// Returns the common header for this RTCP packet.
40    fn header_data(&self) -> [u8; 4];
41}
42
43/// Extension trait providing helper functions for particular pieces of data in the 4 byte RTCP
44/// header provided by [`RtcpPacketParser`].
45pub trait RtcpPacketParserExt<'a>: RtcpPacketParser<'a> {
46    /// The RTCP protocol version.
47    fn version(&self) -> u8 {
48        utils::parser::parse_version(&self.header_data())
49    }
50
51    /// The RTCP payload type.
52    fn type_(&self) -> u8 {
53        utils::parser::parse_packet_type(&self.header_data())
54    }
55
56    /// The sub type of the RTCP packet.  (Same value as [`count`](Self::count)).
57    fn subtype(&self) -> u8 {
58        utils::parser::parse_count(&self.header_data())
59    }
60
61    /// The advertsied length (in bytes) of the RTCP packet.
62    fn length(&self) -> usize {
63        utils::parser::parse_length(&self.header_data())
64    }
65
66    /// The number of records in this RTCP packet.  (Same value as [`subtype`](Self::subtype)).
67    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
74/// A Trait with base functions needed for RTCP Packet writers.
75///
76/// Note: this trait must remain [object-safe].
77///
78/// [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
79pub trait RtcpPacketWriter: std::fmt::Debug + Send + Sync {
80    /// Calculates the size required to write this RTCP packet.
81    ///
82    /// Also performs validity checks.
83    fn calculate_size(&self) -> Result<usize, RtcpWriteError>;
84
85    /// Writes this RTCP packet into `buf` without any validity checks.
86    ///
87    /// Uses the length of the buffer for the length field.
88    ///
89    /// Returns the number of bytes written.
90    ///
91    /// # Panic
92    ///
93    /// Panics if the buf is not large enough.
94    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize;
95
96    /// Gets the padding that was configured for this RTCP packet.
97    fn get_padding(&self) -> Option<u8>;
98}
99
100/// Extension providing helpders for writing a [`RtcpPacket`].
101pub trait RtcpPacketWriterExt: RtcpPacketWriter {
102    /// Writes the Custom packet into `buf`.
103    ///
104    /// The default implementation:
105    ///
106    /// * Calls [`RtcpPacketWriter::calculate_size`] for validity checks and size calculation.
107    /// * Checks that the provided buffer is large enough to store this RTCP packet.
108    /// * Writes to the provided buffer using [`RtcpPacketWriter::write_into_unchecked`].
109    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/// Errors that can be produced when parsing a RTCP packet
122#[derive(thiserror::Error, Debug, PartialEq, Eq)]
123#[non_exhaustive]
124pub enum RtcpParseError {
125    /// Unsupported version.  This implementation only deals with version 2.
126    #[error("Unsupported version: {}.  This implementation only deals with version 2.", .0)]
127    UnsupportedVersion(u8),
128    /// The packet was too short to parse
129    #[error("The packet was too short to parse. Expected size: {expected}, actual size encountered: {actual}")]
130    Truncated {
131        /// The expected size
132        expected: usize,
133        /// The actual size encountered
134        actual: usize,
135    },
136    /// The packet was too large to parse
137    #[error("The packet was too large to parse. Expected size: {expected}, actual size encountered: {actual}")]
138    TooLarge {
139        /// The expected size
140        expected: usize,
141        /// The actual size encountered
142        actual: usize,
143    },
144    /// Invalid Padding length 0.
145    #[error("Invalid Padding length 0")]
146    InvalidPadding,
147
148    /// The SDES Value was too large
149    #[error("The SDES Value length {len} was too large (max {max})")]
150    SdesValueTooLarge {
151        /// The length
152        len: usize,
153        /// The maximum length allowed
154        max: u8,
155    },
156
157    /// The SDES PRIV content was too short
158    #[error("The SDES PRIC content length {len} was too short (min {min})")]
159    SdesPrivContentTruncated {
160        /// The length
161        len: usize,
162        /// The minimum length allowed
163        min: u8,
164    },
165
166    /// The SDES PRIV prefix was too large
167    #[error("The SDES PRIV prefix length {len} too large (available {available})")]
168    SdesPrivPrefixTooLarge {
169        /// The length
170        len: usize,
171        /// The maximum length available
172        available: u8,
173    },
174
175    /// This implementation does not handle this packet
176    #[error("This implementation does not handle this packet")]
177    WrongImplementation,
178
179    /// RTCP Packet type mismatch.
180    #[error("RTCP Packet type mismatch. Actual: {actual}, requested {requested}")]
181    PacketTypeMismatch {
182        /// The packet type encountered.
183        actual: u8,
184        /// The requested packet type.
185        requested: u8,
186    },
187
188    /// The TWCC packet contains fewer delta bytes than required by the packet status list
189    #[error("The TWCC packet contains fewer delta bytes than required by the packet status list")]
190    TwccDeltaTruncated,
191
192    /// The TWCC packet contains reserved status bits
193    #[error("The TWCC packet contains reserved status bits")]
194    TwccReservedPacketStatus,
195}
196
197/// Errors produced when writing a packet
198#[derive(thiserror::Error, Debug, PartialEq, Eq)]
199#[non_exhaustive]
200pub enum RtcpWriteError {
201    /// Output buffer is not large enough to fit the resulting buffer.  The requested size is
202    /// returned.
203    #[error("Output buffer is not large enough to fit the resulting buffer. Requested size: {}", .0)]
204    OutputTooSmall(usize),
205
206    /// The provided padding is not a multiple of 4.
207    #[error("The provided padding {padding} is not a multiple of 4")]
208    InvalidPadding {
209        /// The padding value encountered.
210        padding: u8,
211    },
212
213    /// App Subtype was out of range.
214    #[error("App Subtype {subtype} was out of range (max: {max})")]
215    AppSubtypeOutOfRange {
216        /// The subtype value encountered.
217        subtype: u8,
218        /// The maximum allowable value.
219        max: u8,
220    },
221
222    /// APP Packet Name is invalid.  Expecting a sequence of four ASCII characters.
223    #[error("APP Packet Name is invalid.  Expecting a sequence of four ASCII characters.")]
224    InvalidName,
225
226    /// Data length must be a mutliple of 32bits.  The data length is returned.
227    #[error("Data length must be a mutliple of 32bits. Data len: {}", .0)]
228    DataLen32bitMultiple(usize),
229
230    /// Too many Sources specified.
231    #[error("Too many Sources specified. Number of Sources: {count}, max: {max}")]
232    TooManySources {
233        /// The count of sources encountered.
234        count: usize,
235        /// The maximum allowable value.
236        max: u8,
237    },
238
239    /// Reason length was too large.
240    #[error("Reason length {len} was too large (max {max})")]
241    ReasonLenTooLarge {
242        /// The length value encountered.
243        len: usize,
244        /// The maximum allowable value.
245        max: u8,
246    },
247
248    /// Cumulative Lost was too large.
249    #[error("Cumulative Lost {value} was too large (max {max})")]
250    CumulativeLostTooLarge {
251        /// The value encountered.
252        value: u32,
253        /// The maximum allowable value.
254        max: u32,
255    },
256
257    /// Too many Report Blocks specified (max 31).
258    #[error("Too many Report Blocks specified. Number of Report Blocks: {count} max: {max}")]
259    TooManyReportBlocks {
260        /// The number of report blocks encountered.
261        count: usize,
262        /// The maximum allowable value.
263        max: u8,
264    },
265
266    /// Too many SDES Chunks specified.
267    #[error("Too many SDES Chunks specified. Number of SDES Chunks: {count}, max: {max}")]
268    TooManySdesChunks {
269        /// The number of SDES chunks encountered.
270        count: usize,
271        /// The maximum allowable value.
272        max: u8,
273    },
274
275    /// SDES Value length was too large.
276    #[error("SDES Value length {len} was too large (max {max})")]
277    SdesValueTooLarge {
278        /// The length of the SDES value that was encountered.
279        len: usize,
280        /// The maximum allowable value.
281        max: u8,
282    },
283
284    /// The SDES PRIV prefix was too large.
285    #[error("The SDES PRIV prefix length {len} too large (max {max})")]
286    SdesPrivPrefixTooLarge {
287        /// The length of the SDES PRIV prefix that was encountered.
288        len: usize,
289        /// The maximum allowable value.
290        max: u8,
291    },
292
293    /// Unknown Count was out of range.
294    #[error("Unknown Count {count} was out of range (max: {max})")]
295    CountOutOfRange {
296        /// The count value that was encountered.
297        count: u8,
298        /// The maximum allowable value.
299        max: u8,
300    },
301
302    /// Non-last Compound packet padding defined.
303    #[error("Non-last Compound packet padding defined")]
304    NonLastCompoundPacketPadding,
305
306    /// Feedback packet does not have any FCI defined.
307    #[error("Feedback packet does not contain any FCI data")]
308    MissingFci,
309
310    /// Number of NACK's will not fit within a single RTCP packet.
311    #[error("The number of NACK entries will not fit inside a RTCP packet.")]
312    TooManyNack,
313
314    /// Feedback packet does not support this FCI data.
315    #[error("Wrong feedback packet type for the provided FCI data")]
316    FciWrongFeedbackPacketType,
317
318    /// Payload type value out of range.
319    #[error("The RTP payload value is not a valid value")]
320    PayloadTypeInvalid,
321
322    /// Payload type value out of range.
323    #[error("The amount of padding bits are greater than the size of the data")]
324    PaddingBitsTooLarge,
325
326    /// Number of FIR's will not fit within a single RTCP packet.
327    #[error("The number of FIR entries will not fit inside a RTCP packet.")]
328    TooManyFir,
329
330    /// reference time passed to TwccBuilder does not fit into 24 bits.
331    #[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
394/// Prelude module for defined/implementable traits
395pub mod prelude {
396    pub use super::{
397        FciBuilder, FciParser, RtcpPacket, RtcpPacketParser, RtcpPacketParserExt, RtcpPacketWriter,
398        RtcpPacketWriterExt, XrBlockBuilder, XrBlockBuilderExt, XrBlockParser, XrBlockParserExt,
399        XrBlockStaticType,
400    };
401}