rtcp_types/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3/// A Trait defining RTCP Packet structural data.
4pub trait RtcpPacket {
5    const VERSION: u8 = 2;
6    const MAX_COUNT: u8 = 0x1f;
7    const MIN_PACKET_LEN: usize;
8    const PACKET_TYPE: u8;
9}
10
11/// A Trait to ease the implementation of RTCP Packet parsers.
12///
13/// Implementers only need to return the 4 byte RTCP header
14/// from [`RtcpPacketParser::header_data`] to be able to use
15/// the getters for the common RTCP packet fields.
16pub trait RtcpPacketParser<'a>: RtcpPacket + Sized {
17    /// Parses the provided data.
18    ///
19    /// Returns an instance of `Self` if parsing succeeds,
20    /// an `RtcpParseError` otherwise.
21    fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError>;
22
23    /// Returns the common header for this RTCP packet.
24    fn header_data(&self) -> [u8; 4];
25}
26
27pub trait RtcpPacketParserExt<'a>: RtcpPacketParser<'a> {
28    fn version(&self) -> u8 {
29        utils::parser::parse_version(&self.header_data())
30    }
31
32    fn type_(&self) -> u8 {
33        utils::parser::parse_packet_type(&self.header_data())
34    }
35
36    fn subtype(&self) -> u8 {
37        utils::parser::parse_count(&self.header_data())
38    }
39
40    fn length(&self) -> usize {
41        utils::parser::parse_length(&self.header_data())
42    }
43
44    fn count(&self) -> u8 {
45        utils::parser::parse_count(&self.header_data())
46    }
47}
48
49impl<'a, T: RtcpPacketParser<'a>> RtcpPacketParserExt<'a> for T {}
50
51/// A Trait with base functions needed for RTCP Packet writers.
52///
53/// Note: this trait must remain [object-safe].
54///
55/// [object-safe]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
56pub trait RtcpPacketWriter: std::fmt::Debug {
57    /// Calculates the size required to write this RTCP packet.
58    ///
59    /// Also performs validity checks.
60    fn calculate_size(&self) -> Result<usize, RtcpWriteError>;
61
62    /// Writes this RTCP packet into `buf` without any validity checks.
63    ///
64    /// Uses the length of the buffer for the length field.
65    ///
66    /// Returns the number of bytes written.
67    ///
68    /// # Panic
69    ///
70    /// Panics if the buf is not large enough.
71    fn write_into_unchecked(&self, buf: &mut [u8]) -> usize;
72
73    /// Gets the padding that was configured for this RTCP packet.
74    fn get_padding(&self) -> Option<u8>;
75}
76
77pub trait RtcpPacketWriterExt: RtcpPacketWriter {
78    /// Writes the Custom packet into `buf`.
79    ///
80    /// The default implementation:
81    ///
82    /// * Calls [`RtcpPacketWriter::calculate_size`] for validity checks and size calculation.
83    /// * Checks that the provided buffer is large enough to store this RTCP packet.
84    /// * Writes to the provided buffer using [`RtcpPacketWriter::write_into_unchecked`].
85    fn write_into(&self, buf: &mut [u8]) -> Result<usize, RtcpWriteError> {
86        let req_size = self.calculate_size()?;
87        if buf.len() < req_size {
88            return Err(RtcpWriteError::OutputTooSmall(req_size));
89        }
90
91        Ok(self.write_into_unchecked(&mut buf[..req_size]))
92    }
93}
94
95impl<T: RtcpPacketWriter> RtcpPacketWriterExt for T {}
96
97/// Errors that can be produced when parsing a RTCP packet
98#[derive(thiserror::Error, Debug, PartialEq, Eq)]
99pub enum RtcpParseError {
100    /// Unsupported version.  This implementation only deals with version 2.
101    #[error("Unsupported version: {}.  This implementation only deals with version 2.", .0)]
102    UnsupportedVersion(u8),
103    /// The packet was too short to parse
104    #[error("The packet was too short to parse. Expected size: {expected}, actual size encountered: {actual}")]
105    Truncated {
106        /// The expected size
107        expected: usize,
108        /// The actual size encountered
109        actual: usize,
110    },
111    /// The packet was too large to parse
112    #[error("The packet was too large to parse. Expected size: {expected}, actual size encountered: {actual}")]
113    TooLarge {
114        /// The expected size
115        expected: usize,
116        /// The actual size encountered
117        actual: usize,
118    },
119    /// Invalid Padding length 0.
120    #[error("Invalid Padding length 0")]
121    InvalidPadding,
122
123    /// The SDES Value was too large
124    #[error("The SDES Value length {len} was too large (max {max})")]
125    SdesValueTooLarge {
126        /// The length
127        len: usize,
128        /// The maximum length allowed
129        max: u8,
130    },
131
132    /// The SDES PRIV content was too short
133    #[error("The SDES PRIC content length {len} was too short (min {min})")]
134    SdesPrivContentTruncated {
135        /// The length
136        len: usize,
137        /// The minimum length allowed
138        min: u8,
139    },
140
141    /// The SDES PRIV prefix was too large
142    #[error("The SDES PRIV prefix length {len} too large (available {available})")]
143    SdesPrivPrefixTooLarge {
144        /// The length
145        len: usize,
146        /// The maximum length available
147        available: u8,
148    },
149
150    /// This implementation does not handle this packet
151    #[error("This implementation does not handle this packet")]
152    WrongImplementation,
153
154    /// RTCP Packet type mismatch.
155    #[error("RTCP Packet type mismatch. Actual: {actual}, requested {requested}")]
156    PacketTypeMismatch { actual: u8, requested: u8 },
157}
158
159/// Errors produced when writing a packet
160#[derive(thiserror::Error, Debug, PartialEq, Eq)]
161pub enum RtcpWriteError {
162    /// Output buffer is not large enough to fit the resulting buffer.  The requested size is
163    /// returned.
164    #[error("Output buffer is not large enough to fit the resulting buffer. Requested size: {}", .0)]
165    OutputTooSmall(usize),
166
167    /// The provided padding is not a multiple of 4.
168    #[error("The provided padding {padding} is not a multiple of 4")]
169    InvalidPadding { padding: u8 },
170
171    /// App Subtype was out of range.
172    #[error("App Subtype {subtype} was out of range (max: {max})")]
173    AppSubtypeOutOfRange { subtype: u8, max: u8 },
174
175    /// APP Packet Name is invalid.  Expecting a sequence of four ASCII characters.
176    #[error("APP Packet Name is invalid.  Expecting a sequence of four ASCII characters.")]
177    InvalidName,
178
179    /// Data length must be a mutliple of 32bits.  The data length is returned.
180    #[error("Data length must be a mutliple of 32bits. Data len: {}", .0)]
181    DataLen32bitMultiple(usize),
182
183    /// Too many Sources specified.
184    #[error("Too many Sources specified. Number of Sources: {count}, max: {max}")]
185    TooManySources { count: usize, max: u8 },
186
187    /// Reason length was too large.
188    #[error("Reason length {len} was too large (max {max})")]
189    ReasonLenTooLarge { len: usize, max: u8 },
190
191    /// Cumulative Lost was too large.
192    #[error("Cumulative Lost {value} was too large (max {max})")]
193    CumulativeLostTooLarge { value: u32, max: u32 },
194
195    /// Too many Report Blocks specified (max 31).
196    #[error("Too many Report Blocks specified. Number of Report Blocks: {count} max: {max}")]
197    TooManyReportBlocks { count: usize, max: u8 },
198
199    /// Too many SDES Chunks specified.
200    #[error("Too many SDES Chunks specified. Number of SDES Chunks: {count}, max: {max}")]
201    TooManySdesChunks { count: usize, max: u8 },
202
203    /// SDES Value length was too large.
204    #[error("SDES Value length {len} was too large (max {max})")]
205    SdesValueTooLarge { len: usize, max: u8 },
206
207    /// The SDES PRIV prefix was too large.
208    #[error("The SDES PRIV prefix length {len} too large (max {max})")]
209    SdesPrivPrefixTooLarge { len: usize, max: u8 },
210
211    /// Unknown Count was out of range.
212    #[error("Unknown Count {count} was out of range (max: {max})")]
213    CountOutOfRange { count: u8, max: u8 },
214
215    /// Non-last Compound packet padding defined.
216    #[error("Non-last Compound packet padding defined")]
217    NonLastCompoundPacketPadding,
218
219    /// Feedback packet does not have any FCI defined.
220    #[error("Feedback packet does not contain any FCI data")]
221    MissingFci,
222
223    /// Number of NACK's will not fit within a single RTCP packet.
224    #[error("The number of NACK entries will not fit inside a RTCP packet.")]
225    TooManyNack,
226
227    /// Feedback packet does not support this FCI data.
228    #[error("Wrong feedback packet type for the provided FCI data")]
229    FciWrongFeedbackPacketType,
230
231    /// Payload type value out of range.
232    #[error("The RTP payload value is not a valid value")]
233    PayloadTypeInvalid,
234
235    /// Payload type value out of range.
236    #[error("The amount of padding bits are greater than the size of the data")]
237    PaddingBitsTooLarge,
238
239    /// Number of FIR's will not fit within a single RTCP packet.
240    #[error("The number of FIR entries will not fit inside a RTCP packet.")]
241    TooManyFir,
242}
243
244impl From<RtcpParseError> for RtcpWriteError {
245    fn from(err: RtcpParseError) -> Self {
246        match err {
247            RtcpParseError::SdesValueTooLarge { len, max } => {
248                RtcpWriteError::SdesValueTooLarge { len, max }
249            }
250            RtcpParseError::SdesPrivPrefixTooLarge { len, available } => {
251                RtcpWriteError::SdesPrivPrefixTooLarge {
252                    len,
253                    max: available,
254                }
255            }
256            other => unreachable!("{other}"),
257        }
258    }
259}
260
261mod app;
262mod bye;
263mod compound;
264mod feedback;
265mod receiver;
266mod report_block;
267mod sdes;
268mod sender;
269pub mod utils;
270
271pub use app::{App, AppBuilder};
272pub use bye::{Bye, ByeBuilder};
273pub use compound::{Compound, CompoundBuilder, Packet, PacketBuilder, Unknown, UnknownBuilder};
274pub use feedback::fir::{Fir, FirBuilder, FirEntry};
275pub use feedback::nack::{Nack, NackBuilder};
276pub use feedback::pli::{Pli, PliBuilder};
277pub use feedback::rpsi::{Rpsi, RpsiBuilder};
278pub use feedback::sli::{Sli, SliBuilder};
279pub use feedback::{
280    FciBuilder, FciParser, PayloadFeedback, PayloadFeedbackBuilder, TransportFeedback,
281    TransportFeedbackBuilder,
282};
283pub use receiver::{ReceiverReport, ReceiverReportBuilder};
284pub use report_block::{ReportBlock, ReportBlockBuilder};
285pub use sdes::{Sdes, SdesBuilder, SdesChunk, SdesChunkBuilder, SdesItem, SdesItemBuilder};
286pub use sender::{SenderReport, SenderReportBuilder};
287
288pub mod prelude {
289    pub use super::{
290        FciBuilder, FciParser, RtcpPacket, RtcpPacketParser, RtcpPacketParserExt, RtcpPacketWriter,
291        RtcpPacketWriterExt,
292    };
293}