rtp_parse/rtp2/
rtp_packet.rs

1use std::fmt::{Debug, Display};
2
3use parsely_rs::*;
4
5use super::{header_extensions::SomeHeaderExtension, rtp_header::RtpHeader};
6
7/// https://tools.ietf.org/html/rfc3550#section-5.1
8///  0                   1                   2                   3
9///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
10/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11/// |V=2|P|X|  CC   |M|     PT      |       sequence number         |
12/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13/// |                           timestamp                           |
14/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15/// |           synchronization source (SSRC) identifier            |
16/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
17/// |            contributing source (CSRC) identifiers             |
18/// |                             ....                              |
19/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
20/// |              ...extensions (if present)...                    |
21/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22/// |                   payload                                     |
23/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24#[derive(Debug)]
25pub struct RtpPacket {
26    header: RtpHeader,
27    payload: Bits,
28}
29
30impl Display for RtpPacket {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{:x?}", self.payload.as_ref())
33    }
34}
35
36impl RtpPacket {
37    pub fn payload_type(&self) -> u7 {
38        self.header.payload_type
39    }
40
41    pub fn ssrc(&self) -> u32 {
42        self.header.ssrc
43    }
44
45    pub fn get_extension_by_id(&self, id: u8) -> Option<&SomeHeaderExtension> {
46        self.header.extensions.get_by_id(id)
47    }
48
49    // TODO: this will give the "original" size of the packet, is that best? It's what we want for
50    // incoming stats, but at other point we'll want the "actual" size of the packet (which may
51    // have changed)
52    pub fn size_bytes(&self) -> usize {
53        todo!()
54        // self.header.len() + self.header_exts_buf.len() + self.payload.len()
55    }
56}
57
58impl ParselyRead<Bits> for RtpPacket {
59    type Ctx = ();
60
61    fn read<T: parsely_rs::ByteOrder>(
62        buf: &mut Bits,
63        _ctx: Self::Ctx,
64    ) -> parsely_rs::ParselyResult<Self> {
65        let header = RtpHeader::read::<T>(buf, ()).context("Reading field 'header'")?;
66        let payload = buf.clone();
67
68        Ok(Self { header, payload })
69    }
70}
71
72#[cfg(test)]
73mod test {
74    use crate::rtp2::header_extensions::{HeaderExtensions, OneByteHeaderExtension};
75
76    use super::*;
77
78    #[test]
79    fn test_read_rtp_packet() {
80        #[rustfmt::skip]
81        let mut bits = Bits::from_static_bytes(&[
82            0x90, 0xef, 0x16, 0xad, 
83            0x65, 0xf3, 0xe1, 0x4e, 
84            0x32, 0x0f, 0x22, 0x3a, 
85            // Extensions
86            0xbe, 0xde, 0x00, 0x01, 
87            0x10, 0xff, 0x00, 0x00, 
88            // Payload
89            0x78, 0x0b, 0xe4, 0xc1, 0x36, 0xec, 0xc5, 0x8d,
90            0x8c, 0x49, 0x46, 0x99, 0x04, 0xc5, 0xaa, 0xed, 
91            0x92, 0xe7, 0x63, 0x4a, 0x3a, 0x18, 0x98, 0xee, 
92            0x62, 0xcb, 0x60, 0xff, 0x6c, 0x1b, 0x29, 0x00,
93        ]);
94
95        let mut extensions = HeaderExtensions::default();
96        extensions.add_extension(OneByteHeaderExtension::new(
97            u4::new(1),
98            Bits::from_static_bytes(&[0xFF]),
99        ));
100        let expected_header = RtpHeader {
101            version: u2::new(2),
102            has_padding: false,
103            has_extensions: true,
104            csrc_count: u4::new(0),
105            marked: true,
106            payload_type: u7::new(111),
107            seq_num: 5805,
108            timestamp: 1710481742,
109            ssrc: 839852602,
110            csrcs: vec![],
111            extensions,
112        };
113        #[rustfmt::skip]
114        let expected_payload = Bits::from_static_bytes(&[
115            0x78, 0x0b, 0xe4, 0xc1, 0x36, 0xec, 0xc5, 0x8d,
116            0x8c, 0x49, 0x46, 0x99, 0x04, 0xc5, 0xaa, 0xed, 
117            0x92, 0xe7, 0x63, 0x4a, 0x3a, 0x18, 0x98, 0xee, 
118            0x62, 0xcb, 0x60, 0xff, 0x6c, 0x1b, 0x29, 0x00,
119        ]);
120
121        let packet = RtpPacket::read::<NetworkOrder>(&mut bits, ()).unwrap();
122        assert_eq!(packet.header, expected_header);
123        assert_eq!(packet.payload, expected_payload);
124    }
125}