rtp_rs/
reader.rs

1use std::fmt;
2use crate::{Seq, RtpPacketBuilder};
3
4/// Wrapper around a byte-slice of RTP data, providing accessor methods for the RTP header fields.
5pub struct RtpReader<'a> {
6    buf: &'a [u8],
7}
8
9/// Reasons for `RtpHeader::new()` to fail
10#[derive(Debug)]
11pub enum RtpReaderError {
12    /// Buffer too short to be valid RTP packet
13    BufferTooShort(usize),
14    /// Only RTP version 2 supported
15    UnsupportedVersion(u8),
16    /// RTP headers truncated before end of buffer
17    HeadersTruncated {
18        /// The amount of data which was expected to be present (which may vary depending on flags
19        /// in the RTP header)
20        header_len: usize,
21        /// The actual amount of data that was available, which was found to be smaller than
22        /// `header_len`
23        buffer_len: usize,
24    },
25    /// The padding header at the end of the packet, if present, specifies the number of padding
26    /// bytes, including itself, and therefore cannot be less than `1`, or greater than the
27    /// available space.
28    PaddingLengthInvalid(u8),
29}
30
31impl<'a> RtpReader<'a> {
32    /// An RTP packet header is no fewer than 12 bytes long
33    pub const MIN_HEADER_LEN: usize = 12;
34    const EXTENSION_HEADER_LEN: usize = 4;
35
36    /// Tries to construct a new `RtpHeader` instance, or an `RtpReaderError` if the RTP data is
37    /// malformed.
38    ///
39    /// In particular, if there is too little data in the given buffer, such that some later
40    /// attempt to access an RTP header field would need to access bytes that are not available,
41    /// then this method will fail up front, rather than allowing attempts to access any header
42    /// field to fail later on.
43    pub fn new(b: &'a [u8]) -> Result<RtpReader<'_>, RtpReaderError> {
44        if b.len() < Self::MIN_HEADER_LEN {
45            return Err(RtpReaderError::BufferTooShort(b.len()));
46        }
47        let r = RtpReader { buf: b };
48        if r.version() != 2 {
49            return Err(RtpReaderError::UnsupportedVersion(r.version()));
50        }
51        if r.extension_flag() {
52            let extension_start = r.csrc_end() + Self::EXTENSION_HEADER_LEN;
53            if extension_start > b.len() {
54                return Err(RtpReaderError::HeadersTruncated {
55                    header_len: extension_start,
56                    buffer_len: b.len(),
57                });
58            }
59            let extension_end = extension_start + r.extension_len();
60            if extension_end > b.len() {
61                return Err(RtpReaderError::HeadersTruncated {
62                    header_len: extension_end,
63                    buffer_len: b.len(),
64                });
65            }
66        }
67        if r.payload_offset() > b.len() {
68            return Err(RtpReaderError::HeadersTruncated {
69                header_len: r.payload_offset(),
70                buffer_len: b.len(),
71            });
72        }
73        if r.padding_flag() {
74            let post_header_bytes =  b.len() - r.payload_offset();
75            // with 'padding' flag set, there must be at least a single byte after the headers to
76            // hold the padding length
77            if post_header_bytes == 0 {
78                return Err(RtpReaderError::HeadersTruncated {
79                    header_len: r.payload_offset(),
80                    buffer_len: b.len() - 1,
81                });
82            }
83            let pad_len = r.padding_len()?;
84
85            if r.payload_offset() + pad_len as usize > b.len() {
86                return Err(RtpReaderError::PaddingLengthInvalid(pad_len));
87            }
88        }
89        Ok(r)
90    }
91
92    /// Version field value (currently only version 2 is supported, so other values will not be
93    /// seen from this release of `rtp-rs`.
94    pub fn version(&self) -> u8 {
95        (self.buf[0] & 0b1100_0000) >> 6
96    }
97
98    /// Flag indicating if padding is present at the end of the payload data.
99    fn padding_flag(&self) -> bool {
100        (self.buf[0] & 0b0010_0000) != 0
101    }
102    /// Returns the size of the padding at the end of this packet, or `None` if the padding flag is
103    /// not set in the packet header
104    pub fn padding(&self) -> Option<u8> {
105        if self.padding_flag() {
106            Some(self.padding_len().unwrap())
107        } else {
108            None
109        }
110    }
111
112    fn extension_flag(&self) -> bool {
113        (self.buf[0] & 0b0001_0000) != 0
114    }
115    /// A count of the number of CSRC fields present in the RTP headers - may be `0`.
116    ///
117    /// See [csrc()](#method.csrc).
118    pub fn csrc_count(&self) -> u8 {
119        self.buf[0] & 0b0000_1111
120    }
121    /// A 'marker', which may have some definition in the specific RTP profile in use
122    pub fn mark(&self) -> bool {
123        (self.buf[1] & 0b1000_0000) != 0
124    }
125    /// Indicates the type of content carried in this RTP packet.
126    ///
127    /// A few types-values are defined in the standard, but in many applications of RTP the value
128    /// of this field needs to be agreed between sender and receiver by some mechanism outside of
129    /// RTP itself.
130    pub fn payload_type(&self) -> u8 {
131        self.buf[1] & 0b0111_1111
132    }
133    /// The sequence number of this particular packet.
134    ///
135    /// Sequence numbers are 16 bits, and will wrap back to `0` after reaching the maximum 16-bit
136    /// value of `65535`.
137    ///
138    /// Receivers can identify packet losses or reordering by inspecting the value of this field
139    /// across a sequence of received packets.  The [`Seq`](struct.Seq.html) wrapper type helps
140    /// calling code reason about sequence number problems in the face of any wraparound that might
141    /// have legitimately happened.
142    pub fn sequence_number(&self) -> Seq {
143        Seq((self.buf[2] as u16) << 8 | (self.buf[3] as u16))
144    }
145    /// The timestamp of this packet, given in a timebase that relates to the particular
146    /// `payload_type` in use.
147    ///
148    /// It is perfectly possible for successive packets in a sequence to have the same value, or
149    /// to have values that differ by arbitrarily large amounts.
150    ///
151    /// Timestamps are 32 bits, and will wrap back to `0` after reaching the maximum 32 bit value
152    /// of `4294967295`.
153    pub fn timestamp(&self) -> u32 {
154        (self.buf[4] as u32) << 24
155            | (self.buf[5] as u32) << 16
156            | (self.buf[6] as u32) << 8
157            | (self.buf[7] as u32)
158    }
159    /// The _synchronisation source_ for this packet.  Many applications of RTP do not use this
160    /// field.
161    pub fn ssrc(&self) -> u32 {
162        (self.buf[8] as u32) << 24
163            | (self.buf[9] as u32) << 16
164            | (self.buf[10] as u32) << 8
165            | (self.buf[11] as u32)
166    }
167    /// A potentially empty list of _contributing sources_ for this packet.  Many applications of
168    /// RTP do not use this field.
169    pub fn csrc(&self) -> impl Iterator<Item = u32> + '_ {
170        self.buf[Self::MIN_HEADER_LEN..]
171            .chunks(4)
172            .take(self.csrc_count() as usize)
173            .map(|b| (b[0] as u32) << 24 | (b[1] as u32) << 16 | (b[2] as u32) << 8 | (b[3] as u32))
174    }
175
176    /// Returns the offset of the payload for the packet
177    pub fn payload_offset(&self) -> usize {
178        let offset = self.csrc_end();
179        if self.extension_flag() {
180            offset + Self::EXTENSION_HEADER_LEN + self.extension_len()
181        } else {
182            offset
183        }
184    }
185
186    fn csrc_end(&self) -> usize {
187        Self::MIN_HEADER_LEN + (4 * self.csrc_count()) as usize
188    }
189
190    /// Returns the payload data of this RTP packet, excluding the packet's headers and any
191    /// optional trailing padding.
192    pub fn payload(&self) -> &'a [u8] {
193        let pad = if self.padding_flag() {
194            // in Self::new(), we already checked this was Ok, and will not attempt an invalid
195            // slice below,
196            self.padding_len().unwrap() as usize
197        } else {
198            0
199        };
200        &self.buf[self.payload_offset()..self.buf.len() - pad]
201    }
202
203    fn extension_len(&self) -> usize {
204        let offset = self.csrc_end();
205        // The 16 bit extension length header gives a length in 32 bit (4 byte) units; 0 is a
206        // valid length.
207        4 * ((self.buf[offset + 2] as usize) << 8 | (self.buf[offset + 3] as usize))
208    }
209
210    // must only be used if padding() returns true
211    fn padding_len(&self) -> Result<u8, RtpReaderError> {
212        match self.buf[self.buf.len() - 1] {
213            0 => Err(RtpReaderError::PaddingLengthInvalid(0)),
214            l => Ok(l),
215        }
216    }
217
218    /// Returns details of the optional RTP header extension field.  If there is an extension,
219    /// the first component of the resulting tuple is the extension id, and the second is a
220    /// byte-slice for the extension data value, to be interpreted by the application.
221    pub fn extension(&self) -> Option<(u16, &'a [u8])> {
222        if self.extension_flag() {
223            let offset = self.csrc_end();
224            let id = (self.buf[offset] as u16) << 8 | (self.buf[offset + 1] as u16);
225            let start = offset + 4;
226            Some((id, &self.buf[start..start + self.extension_len()]))
227        } else {
228            None
229        }
230    }
231
232    /// Create a `RtpPacketBuilder` from this packet.  **Note** that padding from the original
233    /// packet will not be used by default, and must be defined on the resulting `RtpPacketBuilder`
234    /// if required.
235    ///
236    /// The padding is not copied from the original since, while we do know how many padding bytes
237    /// were present, we don't know if the intent was to round to 2 bytes, 4 bytes, etc.  Blindly
238    /// copying the padding could result in an incorrect result _if_ the payload is subsequently
239    /// changed for one with a different length.
240    ///
241    /// If you know your output packets don't need padding, there is nothing more to do, since
242    /// that is the default for the resulting `RtpPacketBulder`.
243    ///
244    /// If you know you output packets need padding to 4 bytes, then you _must_ explicitly specify
245    /// this using `builder.padded(Pad::round_to(4))` even if the source packet was already padded
246    /// to a 4 byte boundary.
247    pub fn create_builder(&self) -> RtpPacketBuilder<'a> {
248        let mut builder = RtpPacketBuilder::new()
249            .payload_type(self.payload_type())
250            .marked(self.mark())
251            .sequence(self.sequence_number())
252            .ssrc(self.ssrc())
253            .timestamp(self.timestamp())
254            .payload(self.payload());
255
256        if let Some(ext) = self.extension() {
257            builder = builder.extension(ext.0, ext.1);
258        }
259
260        for csrc in self.csrc() {
261            builder = builder.add_csrc(csrc);
262        }
263
264        builder
265    }
266}
267impl<'a> fmt::Debug for RtpReader<'a> {
268    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
269        f.debug_struct("RtpReader")
270            .field("version", &self.version())
271            .field("padding", &self.padding())
272            .field("extension", &self.extension().map(|(id, _)| id))
273            .field("csrc_count", &self.csrc_count())
274            .field("mark", &self.mark())
275            .field("payload_type", &self.payload_type())
276            .field("sequence_number", &self.sequence_number())
277            .field("timestamp", &self.timestamp())
278            .field("ssrc", &self.ssrc())
279            .field("payload_length", &self.payload().len())
280            .finish()
281    }
282}
283
284#[cfg(test)]
285mod tests {
286    use super::*;
287    use crate::IntoSeqIterator;
288
289
290    const TEST_RTP_PACKET: [u8; 391] = [
291        0x80u8, 0xe0u8, 0x27u8, 0x38u8, 0x64u8, 0xe4u8, 0x05u8, 0xa7u8, 0xa2u8, 0x42u8, 0xafu8,
292        0x01u8, 0x3cu8, 0x41u8, 0xa4u8, 0xa3u8, 0x5du8, 0x13u8, 0xf9u8, 0xcau8, 0x2cu8, 0x7eu8,
293        0xa9u8, 0x77u8, 0xaau8, 0xdeu8, 0xf7u8, 0xcau8, 0xa4u8, 0x28u8, 0xfeu8, 0xdfu8, 0xc8u8,
294        0x68u8, 0xf1u8, 0xd9u8, 0x4fu8, 0x69u8, 0x96u8, 0xa0u8, 0x57u8, 0xbau8, 0xfbu8, 0x07u8,
295        0xc4u8, 0xc4u8, 0xd4u8, 0xfeu8, 0xf8u8, 0xc7u8, 0xb2u8, 0x0du8, 0x01u8, 0x12u8, 0x14u8,
296        0x36u8, 0x69u8, 0x75u8, 0xf2u8, 0xb4u8, 0xb5u8, 0xf2u8, 0x54u8, 0x2eu8, 0xc2u8, 0x66u8,
297        0x51u8, 0xebu8, 0x41u8, 0x80u8, 0x96u8, 0xceu8, 0x8eu8, 0x60u8, 0xb2u8, 0x44u8, 0xaeu8,
298        0xe5u8, 0x43u8, 0xadu8, 0x7bu8, 0x48u8, 0x89u8, 0x44u8, 0xb0u8, 0x48u8, 0x67u8, 0x6au8,
299        0x84u8, 0x7au8, 0x0au8, 0x8fu8, 0x71u8, 0x50u8, 0x69u8, 0xe6u8, 0xb1u8, 0x05u8, 0x40u8,
300        0xb9u8, 0x8cu8, 0xafu8, 0x42u8, 0xcbu8, 0x58u8, 0x83u8, 0xcbu8, 0x32u8, 0x64u8, 0xd2u8,
301        0x2au8, 0x7du8, 0x4eu8, 0xf5u8, 0xbcu8, 0x33u8, 0xfeu8, 0xb7u8, 0x0cu8, 0xe4u8, 0x8eu8,
302        0x38u8, 0xbcu8, 0x3au8, 0x1eu8, 0xd2u8, 0x56u8, 0x13u8, 0x23u8, 0x47u8, 0xcfu8, 0x42u8,
303        0xa9u8, 0xbbu8, 0xcfu8, 0x48u8, 0xf3u8, 0x11u8, 0xc7u8, 0xfdu8, 0x73u8, 0x2du8, 0xe1u8,
304        0xeau8, 0x47u8, 0x5cu8, 0x5du8, 0x11u8, 0x96u8, 0x1eu8, 0xc4u8, 0x70u8, 0x32u8, 0x77u8,
305        0xabu8, 0x31u8, 0x7au8, 0xb1u8, 0x22u8, 0x14u8, 0x8du8, 0x2bu8, 0xecu8, 0x3du8, 0x67u8,
306        0x97u8, 0xa4u8, 0x40u8, 0x21u8, 0x1eu8, 0xceu8, 0xb0u8, 0x63u8, 0x01u8, 0x75u8, 0x77u8,
307        0x03u8, 0x15u8, 0xcdu8, 0x35u8, 0xa1u8, 0x2fu8, 0x4bu8, 0xa0u8, 0xacu8, 0x8du8, 0xd7u8,
308        0x78u8, 0x02u8, 0x23u8, 0xcbu8, 0xfdu8, 0x82u8, 0x4eu8, 0x0bu8, 0x79u8, 0x7fu8, 0x39u8,
309        0x70u8, 0x26u8, 0x66u8, 0x37u8, 0xe9u8, 0x93u8, 0x91u8, 0x7bu8, 0xc4u8, 0x80u8, 0xa9u8,
310        0x18u8, 0x23u8, 0xb3u8, 0xa1u8, 0x04u8, 0x72u8, 0x53u8, 0xa0u8, 0xb4u8, 0xffu8, 0x79u8,
311        0x1fu8, 0x07u8, 0xe2u8, 0x5du8, 0x01u8, 0x7du8, 0x63u8, 0xc1u8, 0x16u8, 0x89u8, 0x23u8,
312        0x4au8, 0x17u8, 0xbbu8, 0x6du8, 0x0du8, 0x81u8, 0x1au8, 0xbbu8, 0x94u8, 0x5bu8, 0xcbu8,
313        0x2du8, 0xdeu8, 0x98u8, 0x40u8, 0x22u8, 0x62u8, 0x41u8, 0xc2u8, 0x9bu8, 0x95u8, 0x85u8,
314        0x60u8, 0xf0u8, 0xdeu8, 0x6fu8, 0xeeu8, 0x93u8, 0xccu8, 0x15u8, 0x76u8, 0xfbu8, 0xf8u8,
315        0x8au8, 0x1du8, 0xe1u8, 0x83u8, 0x12u8, 0xabu8, 0x25u8, 0x6au8, 0x7bu8, 0x89u8, 0xedu8,
316        0x70u8, 0x4eu8, 0xcdu8, 0x1eu8, 0xa9u8, 0xfcu8, 0xa8u8, 0x22u8, 0x91u8, 0x5fu8, 0x50u8,
317        0x68u8, 0x6au8, 0x35u8, 0xf7u8, 0xc1u8, 0x1eu8, 0x15u8, 0x37u8, 0xb4u8, 0x30u8, 0x62u8,
318        0x56u8, 0x1eu8, 0x2eu8, 0xe0u8, 0x2du8, 0xa4u8, 0x1eu8, 0x75u8, 0x5bu8, 0xc7u8, 0xd0u8,
319        0x5bu8, 0x9du8, 0xd0u8, 0x25u8, 0x76u8, 0xdfu8, 0xa7u8, 0x19u8, 0x12u8, 0x93u8, 0xf4u8,
320        0xebu8, 0x02u8, 0xf2u8, 0x4au8, 0x13u8, 0xe9u8, 0x1cu8, 0x17u8, 0xccu8, 0x11u8, 0x87u8,
321        0x9cu8, 0xa6u8, 0x40u8, 0x27u8, 0xb7u8, 0x2bu8, 0x9bu8, 0x6fu8, 0x23u8, 0x06u8, 0x2cu8,
322        0xc6u8, 0x6eu8, 0xc1u8, 0x9au8, 0xbdu8, 0x59u8, 0x37u8, 0xe9u8, 0x9eu8, 0x76u8, 0xf6u8,
323        0xc1u8, 0xbcu8, 0x81u8, 0x18u8, 0x60u8, 0xc9u8, 0x64u8, 0x0au8, 0xb3u8, 0x6eu8, 0xf3u8,
324        0x6bu8, 0xb9u8, 0xd0u8, 0xf6u8, 0xe0u8, 0x9bu8, 0x91u8, 0xc1u8, 0x0fu8, 0x96u8, 0xefu8,
325        0xbcu8, 0x5fu8, 0x8eu8, 0x86u8, 0x56u8, 0x5au8, 0xfcu8, 0x7au8, 0x8bu8, 0xddu8, 0x9au8,
326        0x1cu8, 0xf6u8, 0xb4u8, 0x85u8, 0xf4u8, 0xb0u8,
327    ];
328
329    const TEST_RTP_PACKET_WITH_EXTENSION: [u8; 63] = [
330        144u8,  111u8,  79u8,  252u8,  224u8,  94u8,  104u8,  203u8,  30u8,  112u8,  208u8,
331        191u8,  190u8,  222u8,  0u8,  3u8,  34u8,  175u8,  185u8,  88u8,  49u8,  0u8,  171u8,
332        64u8,  48u8,  16u8,  219u8,  0u8,  104u8,  9u8,  136u8,  90u8,  174u8,  145u8,  68u8,
333        165u8,  227u8,  178u8,  187u8,  68u8,  166u8,  66u8,  235u8,  40u8,  171u8,  135u8,
334        30u8,  174u8,  130u8,  239u8,  205u8,  14u8,  211u8,  232u8,  65u8,  67u8,  153u8,
335        120u8,  63u8,  17u8,  101u8,  55u8,  17u8
336    ];
337
338    #[test]
339    fn version() {
340        let reader = RtpReader::new(&TEST_RTP_PACKET).unwrap();
341        assert_eq!(2, reader.version());
342        assert!(reader.padding().is_none());
343        assert!(reader.extension().is_none());
344        assert_eq!(0, reader.csrc_count());
345        assert!(reader.mark());
346        assert_eq!(96, reader.payload_type());
347        assert_eq!(Seq(10040), reader.sequence_number());
348        assert_eq!(1_692_665_255, reader.timestamp());
349        assert_eq!(0xa242_af01, reader.ssrc());
350        assert_eq!(379, reader.payload().len());
351        format!("{:?}", reader);
352    }
353
354    #[test]
355    fn padding() {
356        let reader = RtpReader::new(&TEST_RTP_PACKET_WITH_EXTENSION).unwrap();
357        assert_eq!(2, reader.version());
358        assert!(reader.padding().is_none());
359        assert!(reader.extension().is_some());
360        assert_eq!(0, reader.csrc_count());
361        assert_eq!(111, reader.payload_type());
362    }
363
364    #[test]
365    fn padding_too_large() {
366        // 'padding' header-flag is on, and padding length (255) in final byte is larger than the
367        // buffer length. (Test data created by fuzzing.)
368        let data = [
369            0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0x90, 0x0, 0x0, 0x1, 0x0, 0xff, 0xa2, 0xa2, 0xa2, 0xa2,
370            0x90, 0x0, 0x0, 0x0, 0x0, 0xff,
371        ];
372        assert!(RtpReader::new(&data).is_err());
373    }
374
375    #[test]
376    fn builder_juggle() {
377        let reader = RtpReader::new(&TEST_RTP_PACKET).unwrap();
378        let buffer = reader.create_builder().build().unwrap();
379
380        assert_eq!(&buffer.as_slice()[..], &TEST_RTP_PACKET[..]);
381    }
382
383    #[test]
384    fn builder_juggle_extension() {
385        let reader = RtpReader::new(&TEST_RTP_PACKET_WITH_EXTENSION).unwrap();
386        let buffer = reader.create_builder().build().unwrap();
387        assert_eq!(&buffer.as_slice()[..], &TEST_RTP_PACKET_WITH_EXTENSION[..]);
388    }
389
390    #[test]
391    fn builder_juggle_clear_payload() {
392        let new_payload = vec![];
393        let reader = RtpReader::new(&TEST_RTP_PACKET_WITH_EXTENSION).unwrap();
394        let buffer = reader.create_builder()
395            .payload(&new_payload).build().unwrap();
396
397        let expected = &TEST_RTP_PACKET_WITH_EXTENSION[0..(3 + 4) * 4];
398        assert_eq!(&buffer.as_slice()[..], expected);
399    }
400
401    #[test]
402    fn seq() {
403        assert!(Seq(0).precedes(Seq(1)));
404        assert!(Seq(0xffff).precedes(Seq(0)));
405        assert!(Seq(0) < Seq(1));
406        assert!(Seq(0xffff) < Seq(0));
407        assert_eq!(-1, Seq(0) - Seq(1));
408        assert_eq!(1, Seq(1) - Seq(0));
409        assert_eq!(0, Seq(1) - Seq(1));
410        assert_eq!(1, Seq(0) - Seq(0xffff));
411        assert_eq!(-1, Seq(0xffff) - Seq(0));
412        let mut it = (Seq(0xfffe)..Seq(1)).seq_iter();
413        assert_eq!(Seq(0xfffe), it.next().unwrap());
414        assert_eq!(Seq(0xffff), it.next().unwrap());
415        assert_eq!(Seq(0x0000), it.next().unwrap());
416        assert_eq!(None, it.next());
417    }
418}