rtp_types/
packet.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::fmt;
4
5/// An error produced when parsing a packet.
6#[derive(Debug, thiserror::Error)]
7pub enum RtpParseError {
8    /// Version is unsupported.  This implementation only supports version 2.
9    #[error("Unsupported RTP version {}", .0)]
10    UnsupportedVersion(u8),
11    /// There is not enough data available to successfully parse the packet
12    #[error("Not enough data available to parse the packet: expected {}, actual {}", .expected, .actual)]
13    Truncated {
14        /// The expected size.
15        expected: usize,
16        /// The actual size encountered.
17        actual: usize,
18    },
19    /// The padding byte does not contain a valid value.
20    #[error("Padding contains invalid value {}", .0)]
21    PaddingInvalid(u8),
22}
23
24/// A parsed RTP packet.  A wrapper around a byte slice.  Each field is only accessed when needed.
25#[repr(transparent)]
26pub struct RtpPacket<'a> {
27    data: &'a [u8],
28}
29
30impl<'a> fmt::Debug for RtpPacket<'a> {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        struct DebugCsrc<'a>(&'a RtpPacket<'a>);
33
34        impl<'a> fmt::Debug for DebugCsrc<'a> {
35            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36                let mut list = f.debug_list();
37
38                for csrc in self.0.csrc() {
39                    list.entry(&csrc);
40                }
41
42                list.finish()
43            }
44        }
45
46        f.debug_struct("RtpPacket")
47            .field("version", &self.version())
48            .field("marker_bit", &self.marker_bit())
49            .field("payload_type", &self.payload_type())
50            .field("sequence_number", &self.sequence_number())
51            .field("timestamp", &self.timestamp())
52            .field("ssrc", &self.ssrc())
53            .field("csrc", &DebugCsrc(self))
54            .field("extension", &self.extension())
55            .field("payload", &self.payload())
56            .field("padding", &self.padding())
57            .finish()
58    }
59}
60
61impl<'a> RtpPacket<'a> {
62    /// The minimum number of bytes a RTP packet must be to be parsed correctly.
63    pub const MIN_RTP_PACKET_LEN: usize = 12;
64
65    /// The maximum number of CSRCs a RTP packet can contain.
66    pub const MAX_N_CSRCS: usize = 0xf;
67
68    /// Parse a byte slice into a [`RtpPacket`].  This implementation prefers to fail fast and will
69    /// return errors when the size of passed in data is not sufficient for values described in the
70    /// data.
71    pub fn parse(data: &'a [u8]) -> Result<RtpPacket<'a>, RtpParseError> {
72        if data.len() < Self::MIN_RTP_PACKET_LEN {
73            return Err(RtpParseError::Truncated {
74                expected: Self::MIN_RTP_PACKET_LEN,
75                actual: data.len(),
76            });
77        }
78
79        let ret = Self { data };
80        if ret.version() != 2 {
81            return Err(RtpParseError::UnsupportedVersion(ret.version()));
82        }
83
84        if ret.n_csrcs() > 0 {
85            // aka the end of the list of csrcs
86            let expected = ret.extension_offset();
87            if ret.data.len() < expected {
88                return Err(RtpParseError::Truncated {
89                    expected,
90                    actual: ret.data.len(),
91                });
92            }
93        }
94
95        if ret.extension_bit() {
96            // extension offset plus 4 byte extension header
97            let expected = ret.extension_offset() + 4;
98            if ret.data.len() < expected {
99                return Err(RtpParseError::Truncated {
100                    expected,
101                    actual: ret.data.len(),
102                });
103            }
104            let expected = expected + ret.extension_len();
105            if ret.data.len() < expected {
106                return Err(RtpParseError::Truncated {
107                    expected,
108                    actual: ret.data.len(),
109                });
110            }
111        }
112
113        if ret.padding_bit() {
114            // offset of the payload plus at least one byte for the ending padding byte
115            let expected = ret.payload_offset() + 1;
116            if ret.data.len() < expected {
117                return Err(RtpParseError::Truncated {
118                    expected,
119                    actual: ret.data.len(),
120                });
121            }
122            let padding_len = ret.padding().unwrap();
123            // padding must be >= 1
124            if padding_len == 0 {
125                return Err(RtpParseError::PaddingInvalid(0));
126            }
127            let expected = ret.payload_offset() + padding_len as usize;
128            if ret.data.len() < expected {
129                // padding extends (at least) back into the RTP header
130                return Err(RtpParseError::Truncated {
131                    expected,
132                    actual: ret.data.len(),
133                });
134            }
135        }
136        Ok(ret)
137    }
138
139    /// The RTP version in this packet.  Only version 2 is supported.
140    pub fn version(&self) -> u8 {
141        (self.data[0] & 0b1100_0000) >> 6
142    }
143
144    /// Returns whether the padding bit is set for this packet.
145    pub fn padding_bit(&self) -> bool {
146        self.data[0] & 0b0010_0000 != 0
147    }
148
149    /// Returns the number of bytes of padding used by this packet or `None`.
150    pub fn padding(&self) -> Option<u8> {
151        if self.padding_bit() {
152            Some(self.data[self.data.len() - 1])
153        } else {
154            None
155        }
156    }
157
158    /// Returns whether the extension bit is set for this packet.
159    pub fn extension_bit(&self) -> bool {
160        (self.data[0] & 0b0001_0000) != 0
161    }
162
163    /// Returns the number of Contribution Sources for this packet.  May not be used by this
164    /// packet.
165    pub fn n_csrcs(&self) -> u8 {
166        self.data[0] & 0b0000_1111
167    }
168
169    /// Returns whether the marker bit is set for this packet.  The meaning of the marker bit
170    /// is payload-specific.
171    #[deprecated = "Use `marker_bit()` instead"]
172    pub fn marker(&self) -> bool {
173        self.marker_bit()
174    }
175
176    /// Returns whether the marker bit is set for this packet.  The meaning of the marker bit
177    /// is payload-specific.
178    pub fn marker_bit(&self) -> bool {
179        (self.data[1] & 0b1000_0000) != 0
180    }
181
182    /// Returns the payload type for this packet.
183    pub fn payload_type(&self) -> u8 {
184        self.data[1] & 0b0111_1111
185    }
186
187    /// Returns the sequence number for this packet.
188    pub fn sequence_number(&self) -> u16 {
189        (self.data[2] as u16) << 8 | self.data[3] as u16
190    }
191
192    /// Returns the RTP timestamp for this packet
193    pub fn timestamp(&self) -> u32 {
194        (self.data[4] as u32) << 24
195            | (self.data[5] as u32) << 16
196            | (self.data[6] as u32) << 8
197            | (self.data[7] as u32)
198    }
199
200    /// Returns the Sychronisation Source for this packet.
201    pub fn ssrc(&self) -> u32 {
202        (self.data[8] as u32) << 24
203            | (self.data[9] as u32) << 16
204            | (self.data[10] as u32) << 8
205            | (self.data[11] as u32)
206    }
207
208    /// Returns a (potentially empty) iterator over the Contribution Sources for this packet.
209    pub fn csrc(&self) -> impl Iterator<Item = u32> + '_ {
210        self.data[Self::MIN_RTP_PACKET_LEN..]
211            .chunks_exact(4)
212            .take(self.n_csrcs() as usize)
213            .map(|bytes| {
214                (bytes[0] as u32) << 24
215                    | (bytes[1] as u32) << 16
216                    | (bytes[2] as u32) << 8
217                    | bytes[3] as u32
218            })
219    }
220
221    pub(crate) fn extension_offset(&self) -> usize {
222        Self::MIN_RTP_PACKET_LEN + (self.n_csrcs() as usize) * 4
223    }
224
225    /// Returns the length of the extension data in this packet.
226    pub fn extension_len(&self) -> usize {
227        if self.extension_bit() {
228            let offset = self.extension_offset();
229            4 * ((self.data[offset + 2] as usize) << 8 | self.data[offset + 3] as usize)
230        } else {
231            0
232        }
233    }
234
235    /// Returns the extension data for this packet.  The first value is an identifier and is
236    /// 'defined by the RTP profile'.  The second value is the extension data.
237    pub fn extension(&self) -> Option<(u16, &[u8])> {
238        if self.extension_bit() {
239            let offset = self.extension_offset();
240            let id = (self.data[offset] as u16) << 8 | self.data[offset + 1] as u16;
241            let offset = offset + 4;
242            Some((id, &self.data[offset..][..self.extension_len()]))
243        } else {
244            None
245        }
246    }
247
248    /// Returns the offset of the payload in this packet relative to the beginning of the packet.
249    pub fn payload_offset(&self) -> usize {
250        self.extension_offset()
251            + if self.extension_bit() {
252                self.extension_len() + 4
253            } else {
254                0
255            }
256    }
257
258    /// Returns the length of the payload in this packet without padding.
259    pub fn payload_len(&self) -> usize {
260        let offset = self.payload_offset();
261        let pad = self.padding().unwrap_or_default() as usize;
262
263        self.data.len() - pad - offset
264    }
265
266    /// Returns the payload data.
267    pub fn payload(&self) -> &[u8] {
268        let offset = self.payload_offset();
269        let pad = self.padding().unwrap_or_default() as usize;
270        &self.data[offset..self.data.len() - pad]
271    }
272
273    /// Creates a builder that will be able to reconstruct this packet byte for byte (excluding
274    /// any padding bytes).  Any aspect of the returned builder can be modified.
275    pub fn as_builder(&'a self) -> crate::RtpPacketBuilder<&'a [u8], &'a [u8]> {
276        let mut builder = crate::RtpPacketBuilder::new()
277            .marker_bit(self.marker_bit())
278            .payload_type(self.payload_type())
279            .sequence_number(self.sequence_number())
280            .timestamp(self.timestamp())
281            .ssrc(self.ssrc())
282            .payload(self.payload());
283        for csrc in self.csrc() {
284            builder = builder.add_csrc(csrc);
285        }
286        if let Some((ext_id, ext_data)) = self.extension() {
287            builder = builder.extension(ext_id, ext_data);
288        }
289        if let Some(padding) = self.padding() {
290            builder = builder.padding(padding);
291        }
292        builder
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use super::*;
299
300    #[test]
301    fn parse_rtp_no_payload_no_extension_no_csrc() {
302        let data: [u8; 12] = [
303            0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
304        ];
305        let rtp = RtpPacket::parse(data.as_ref()).unwrap();
306        assert_eq!(rtp.version(), 2);
307        assert_eq!(rtp.padding(), None);
308        assert_eq!(rtp.n_csrcs(), 0);
309        assert!(!rtp.marker_bit());
310        assert_eq!(rtp.payload_type(), 96);
311        assert_eq!(rtp.sequence_number(), 0x0102);
312        assert_eq!(rtp.timestamp(), 0x03040506);
313        assert_eq!(rtp.ssrc(), 0x07080910);
314        assert_eq!(rtp.csrc().count(), 0);
315        assert_eq!(rtp.extension(), None);
316        assert_eq!(rtp.payload(), &[]);
317        let built = rtp.as_builder().write_vec().unwrap();
318        assert_eq!(built, data.as_ref());
319    }
320
321    #[test]
322    fn parse_truncated_rtp_packet() {
323        let data: [u8; 11] = [
324            0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
325        ];
326        assert!(matches!(
327            RtpPacket::parse(data.as_ref()),
328            Err(RtpParseError::Truncated {
329                expected: 12,
330                actual: 11
331            })
332        ));
333    }
334
335    #[test]
336    fn parse_rtp_with_csrc() {
337        let data: [u8; 16] = [
338            0x81, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12,
339            0x13, 0x14,
340        ];
341        let rtp = RtpPacket::parse(data.as_ref()).unwrap();
342        assert_eq!(rtp.version(), 2);
343        assert_eq!(rtp.padding(), None);
344        assert_eq!(rtp.n_csrcs(), 1);
345        assert!(!rtp.marker_bit());
346        assert_eq!(rtp.payload_type(), 96);
347        assert_eq!(rtp.sequence_number(), 0x0102);
348        assert_eq!(rtp.timestamp(), 0x03040506);
349        assert_eq!(rtp.ssrc(), 0x07080910);
350        let mut csrc = rtp.csrc();
351        assert_eq!(csrc.next(), Some(0x11121314));
352        assert_eq!(csrc.next(), None);
353        assert_eq!(rtp.extension(), None);
354        assert_eq!(rtp.payload(), &[]);
355        let built = rtp.as_builder().write_vec().unwrap();
356        assert_eq!(built, data.as_ref());
357    }
358
359    #[test]
360    fn parse_rtp_with_short_csrc_data() {
361        let data: [u8; 15] = [
362            0x81, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12,
363            0x13,
364        ];
365        assert!(matches!(
366            RtpPacket::parse(data.as_ref()),
367            Err(RtpParseError::Truncated {
368                expected: 16,
369                actual: 15
370            })
371        ));
372    }
373
374    #[test]
375    fn parse_rtp_with_extension() {
376        let data: [u8; 20] = [
377            0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
378            0x00, 0x1, 0x0d, 0x0e, 0x0f, 0x10,
379        ];
380        let rtp = RtpPacket::parse(data.as_ref()).unwrap();
381        assert_eq!(rtp.version(), 2);
382        assert_eq!(rtp.padding(), None);
383        assert_eq!(rtp.n_csrcs(), 0);
384        assert!(!rtp.marker_bit());
385        assert_eq!(rtp.payload_type(), 96);
386        assert_eq!(rtp.sequence_number(), 0x0102);
387        assert_eq!(rtp.timestamp(), 0x03040506);
388        assert_eq!(rtp.ssrc(), 0x0708090a);
389        assert_eq!(rtp.csrc().count(), 0);
390        assert_eq!(
391            rtp.extension(),
392            Some((0x0b0c, [0x0d, 0x0e, 0x0f, 0x10].as_ref()))
393        );
394        assert_eq!(rtp.payload(), &[]);
395        let built = rtp.as_builder().write_vec().unwrap();
396        assert_eq!(built, data.as_ref());
397    }
398
399    #[test]
400    fn parse_rtp_with_short_extension_header() {
401        let data: [u8; 15] = [
402            0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
403            0x00,
404        ];
405        assert!(matches!(
406            RtpPacket::parse(data.as_ref()),
407            Err(RtpParseError::Truncated {
408                expected: 16,
409                actual: 15
410            })
411        ));
412    }
413
414    #[test]
415    fn parse_rtp_with_short_extension_data() {
416        let data: [u8; 19] = [
417            0x90, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
418            0x00, 0x01, 0x0d, 0x0e, 0x0f,
419        ];
420        assert!(matches!(
421            RtpPacket::parse(data.as_ref()),
422            Err(RtpParseError::Truncated {
423                expected: 20,
424                actual: 19
425            })
426        ));
427    }
428
429    #[test]
430    fn parse_rtp_with_payload() {
431        let data: [u8; 16] = [
432            0x80, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
433            0x0d, 0x0e,
434        ];
435        let rtp = RtpPacket::parse(data.as_ref()).unwrap();
436        assert_eq!(rtp.version(), 2);
437        assert_eq!(rtp.padding(), None);
438        assert_eq!(rtp.n_csrcs(), 0);
439        assert!(!rtp.marker_bit());
440        assert_eq!(rtp.payload_type(), 96);
441        assert_eq!(rtp.sequence_number(), 0x0102);
442        assert_eq!(rtp.timestamp(), 0x03040506);
443        assert_eq!(rtp.ssrc(), 0x0708090a);
444        assert_eq!(rtp.csrc().count(), 0);
445        assert_eq!(rtp.extension(), None);
446        assert_eq!(rtp.payload(), &[0x0b, 0x0c, 0x0d, 0x0e]);
447        let built = rtp.as_builder().write_vec().unwrap();
448        assert_eq!(built, data.as_ref());
449    }
450
451    #[test]
452    fn parse_rtp_with_padding() {
453        let data: [u8; 16] = [
454            0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
455            0x00, 0x02,
456        ];
457        let rtp = RtpPacket::parse(data.as_ref()).unwrap();
458        assert_eq!(rtp.version(), 2);
459        assert_eq!(rtp.padding(), Some(2));
460        assert_eq!(rtp.n_csrcs(), 0);
461        assert!(!rtp.marker_bit());
462        assert_eq!(rtp.payload_type(), 96);
463        assert_eq!(rtp.sequence_number(), 0x0102);
464        assert_eq!(rtp.timestamp(), 0x03040506);
465        assert_eq!(rtp.ssrc(), 0x0708090a);
466        assert_eq!(rtp.csrc().count(), 0);
467        assert_eq!(rtp.extension(), None);
468        assert_eq!(rtp.payload(), &[0x0b, 0x0c]);
469        let built = rtp.as_builder().write_vec().unwrap();
470        assert_eq!(built, data.as_ref());
471    }
472
473    #[test]
474    fn parse_rtp_with_too_large_padding() {
475        let data: [u8; 13] = [
476            0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x02,
477        ];
478        assert!(matches!(
479            RtpPacket::parse(data.as_ref()),
480            Err(RtpParseError::Truncated {
481                expected: 14,
482                actual: 13
483            })
484        ));
485    }
486
487    #[test]
488    fn parse_rtp_with_zero_padding_length() {
489        let data: [u8; 13] = [
490            0xa0, 0x60, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x00,
491        ];
492        assert!(matches!(
493            RtpPacket::parse(data.as_ref()),
494            Err(RtpParseError::PaddingInvalid(0))
495        ));
496    }
497}