Skip to main content

rtp_engine/rtp/
header.rs

1//! RTP header structures and parsing.
2
3/// RTP packet header (RFC 3550).
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct RtpHeader {
6    /// RTP version (always 2).
7    pub version: u8,
8    /// Padding flag.
9    pub padding: bool,
10    /// Extension flag.
11    pub extension: bool,
12    /// CSRC count.
13    pub csrc_count: u8,
14    /// Marker bit.
15    pub marker: bool,
16    /// Payload type (0-127).
17    pub payload_type: u8,
18    /// Sequence number (wraps at 65535).
19    pub sequence: u16,
20    /// Timestamp in clock rate units.
21    pub timestamp: u32,
22    /// Synchronization source identifier.
23    pub ssrc: u32,
24    /// Contributing source identifiers (0-15 entries).
25    pub csrc: Vec<u32>,
26    /// Header extension data (if extension flag is set).
27    pub extension_data: Option<Vec<u8>>,
28}
29
30impl RtpHeader {
31    /// Create a new RTP header with default values.
32    pub fn new(payload_type: u8, sequence: u16, timestamp: u32, ssrc: u32) -> Self {
33        Self {
34            version: 2,
35            padding: false,
36            extension: false,
37            csrc_count: 0,
38            marker: false,
39            payload_type,
40            sequence,
41            timestamp,
42            ssrc,
43            csrc: Vec::new(),
44            extension_data: None,
45        }
46    }
47
48    /// Create a header with the marker bit set (e.g., for first packet of a talkspurt).
49    pub fn with_marker(mut self) -> Self {
50        self.marker = true;
51        self
52    }
53
54    /// Parse an RTP header from raw bytes.
55    pub fn parse(data: &[u8]) -> Option<Self> {
56        if data.len() < 12 {
57            return None;
58        }
59
60        let version = (data[0] >> 6) & 0x03;
61        if version != 2 {
62            return None; // Only RTP v2 is supported
63        }
64
65        let padding = (data[0] & 0x20) != 0;
66        let extension = (data[0] & 0x10) != 0;
67        let csrc_count = data[0] & 0x0F;
68        let marker = (data[1] & 0x80) != 0;
69        let payload_type = data[1] & 0x7F;
70        let sequence = u16::from_be_bytes([data[2], data[3]]);
71        let timestamp = u32::from_be_bytes([data[4], data[5], data[6], data[7]]);
72        let ssrc = u32::from_be_bytes([data[8], data[9], data[10], data[11]]);
73
74        let mut header = Self {
75            version,
76            padding,
77            extension,
78            csrc_count,
79            marker,
80            payload_type,
81            sequence,
82            timestamp,
83            ssrc,
84            csrc: Vec::new(),
85            extension_data: None,
86        };
87
88        // Parse CSRC list
89        let csrc_end = 12 + (csrc_count as usize) * 4;
90        if data.len() < csrc_end {
91            return None;
92        }
93        for i in 0..csrc_count as usize {
94            let offset = 12 + i * 4;
95            let csrc = u32::from_be_bytes([
96                data[offset],
97                data[offset + 1],
98                data[offset + 2],
99                data[offset + 3],
100            ]);
101            header.csrc.push(csrc);
102        }
103
104        // Parse extension header if present
105        if extension {
106            if data.len() < csrc_end + 4 {
107                return None;
108            }
109            let ext_len = u16::from_be_bytes([data[csrc_end + 2], data[csrc_end + 3]]) as usize * 4;
110            let ext_end = csrc_end + 4 + ext_len;
111            if data.len() < ext_end {
112                return None;
113            }
114            header.extension_data = Some(data[csrc_end..ext_end].to_vec());
115        }
116
117        Some(header)
118    }
119
120    /// Serialize the header to bytes.
121    pub fn to_bytes(&self) -> Vec<u8> {
122        let mut buf = Vec::with_capacity(12 + self.csrc.len() * 4);
123
124        // First byte: V=2, P, X, CC
125        let byte0 = (self.version << 6)
126            | (if self.padding { 0x20 } else { 0 })
127            | (if self.extension { 0x10 } else { 0 })
128            | (self.csrc.len() as u8 & 0x0F);
129        buf.push(byte0);
130
131        // Second byte: M, PT
132        let byte1 = (if self.marker { 0x80 } else { 0 }) | (self.payload_type & 0x7F);
133        buf.push(byte1);
134
135        // Sequence number
136        buf.extend_from_slice(&self.sequence.to_be_bytes());
137
138        // Timestamp
139        buf.extend_from_slice(&self.timestamp.to_be_bytes());
140
141        // SSRC
142        buf.extend_from_slice(&self.ssrc.to_be_bytes());
143
144        // CSRC list
145        for csrc in &self.csrc {
146            buf.extend_from_slice(&csrc.to_be_bytes());
147        }
148
149        // Extension data
150        if let Some(ref ext) = self.extension_data {
151            buf.extend_from_slice(ext);
152        }
153
154        buf
155    }
156
157    /// Get the total header length in bytes.
158    pub fn header_length(&self) -> usize {
159        let base = 12 + self.csrc.len() * 4;
160        if let Some(ref ext) = self.extension_data {
161            base + ext.len()
162        } else {
163            base
164        }
165    }
166}
167
168impl Default for RtpHeader {
169    fn default() -> Self {
170        Self::new(0, 0, 0, 0)
171    }
172}
173
174/// A complete RTP packet (header + payload).
175#[derive(Debug, Clone)]
176pub struct RtpPacket {
177    /// The RTP header.
178    pub header: RtpHeader,
179    /// The payload data.
180    pub payload: Vec<u8>,
181}
182
183impl RtpPacket {
184    /// Create a new RTP packet.
185    pub fn new(header: RtpHeader, payload: Vec<u8>) -> Self {
186        Self { header, payload }
187    }
188
189    /// Create a packet with just the essential fields.
190    pub fn simple(
191        payload_type: u8,
192        sequence: u16,
193        timestamp: u32,
194        ssrc: u32,
195        payload: Vec<u8>,
196    ) -> Self {
197        Self {
198            header: RtpHeader::new(payload_type, sequence, timestamp, ssrc),
199            payload,
200        }
201    }
202
203    /// Parse an RTP packet from raw bytes.
204    pub fn parse(data: &[u8]) -> Option<Self> {
205        let header = RtpHeader::parse(data)?;
206        let payload_offset = header.header_length();
207        if payload_offset > data.len() {
208            return None;
209        }
210        Some(Self {
211            header,
212            payload: data[payload_offset..].to_vec(),
213        })
214    }
215
216    /// Serialize the packet to bytes.
217    pub fn to_bytes(&self) -> Vec<u8> {
218        let mut buf = self.header.to_bytes();
219        buf.extend_from_slice(&self.payload);
220        buf
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227
228    #[test]
229    fn test_header_roundtrip() {
230        let header = RtpHeader::new(8, 1234, 160000, 0xDEADBEEF);
231        let bytes = header.to_bytes();
232        let parsed = RtpHeader::parse(&bytes).unwrap();
233
234        assert_eq!(header.payload_type, parsed.payload_type);
235        assert_eq!(header.sequence, parsed.sequence);
236        assert_eq!(header.timestamp, parsed.timestamp);
237        assert_eq!(header.ssrc, parsed.ssrc);
238    }
239
240    #[test]
241    fn test_header_with_marker() {
242        let header = RtpHeader::new(0, 1, 160, 0x12345678).with_marker();
243        let bytes = header.to_bytes();
244        assert!(bytes[1] & 0x80 != 0);
245    }
246
247    #[test]
248    fn test_packet_roundtrip() {
249        let packet = RtpPacket::simple(0, 100, 16000, 0xABCDEF01, vec![1, 2, 3, 4, 5]);
250        let bytes = packet.to_bytes();
251        let parsed = RtpPacket::parse(&bytes).unwrap();
252
253        assert_eq!(packet.header.sequence, parsed.header.sequence);
254        assert_eq!(packet.payload, parsed.payload);
255    }
256
257    #[test]
258    fn test_header_with_csrc() {
259        let mut header = RtpHeader::new(0, 1, 160, 0x12345678);
260        header.csrc.push(0xAAAAAAAA);
261        header.csrc.push(0xBBBBBBBB);
262
263        let bytes = header.to_bytes();
264        let parsed = RtpHeader::parse(&bytes).unwrap();
265
266        assert_eq!(parsed.csrc.len(), 2);
267        assert_eq!(parsed.csrc[0], 0xAAAAAAAA);
268        assert_eq!(parsed.csrc[1], 0xBBBBBBBB);
269    }
270
271    #[test]
272    fn test_invalid_version() {
273        // Version 0 packet
274        let data = [
275            0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x12, 0x34, 0x56, 0x78,
276        ];
277        assert!(RtpHeader::parse(&data).is_none());
278    }
279
280    #[test]
281    fn test_packet_too_short() {
282        // Less than 12 bytes
283        assert!(RtpHeader::parse(&[0x80, 0x00, 0x00]).is_none());
284        assert!(RtpHeader::parse(&[]).is_none());
285    }
286
287    #[test]
288    fn test_header_default() {
289        let header = RtpHeader::default();
290        assert_eq!(header.version, 2);
291        assert_eq!(header.payload_type, 0);
292        assert_eq!(header.sequence, 0);
293        assert_eq!(header.timestamp, 0);
294        assert_eq!(header.ssrc, 0);
295        assert!(!header.marker);
296        assert!(!header.padding);
297        assert!(!header.extension);
298    }
299
300    #[test]
301    fn test_all_payload_types() {
302        // Test all valid payload types (0-127)
303        for pt in 0u8..128 {
304            let header = RtpHeader::new(pt, 1, 160, 0x12345678);
305            let bytes = header.to_bytes();
306            let parsed = RtpHeader::parse(&bytes).unwrap();
307            assert_eq!(parsed.payload_type, pt);
308        }
309    }
310
311    #[test]
312    fn test_sequence_wrap() {
313        let header = RtpHeader::new(0, 65535, 160, 0x12345678);
314        let bytes = header.to_bytes();
315        let parsed = RtpHeader::parse(&bytes).unwrap();
316        assert_eq!(parsed.sequence, 65535);
317
318        let header2 = RtpHeader::new(0, 0, 320, 0x12345678);
319        let bytes2 = header2.to_bytes();
320        let parsed2 = RtpHeader::parse(&bytes2).unwrap();
321        assert_eq!(parsed2.sequence, 0);
322    }
323
324    #[test]
325    fn test_timestamp_max() {
326        let header = RtpHeader::new(0, 1, u32::MAX, 0x12345678);
327        let bytes = header.to_bytes();
328        let parsed = RtpHeader::parse(&bytes).unwrap();
329        assert_eq!(parsed.timestamp, u32::MAX);
330    }
331
332    #[test]
333    fn test_header_length() {
334        let mut header = RtpHeader::new(0, 1, 160, 0x12345678);
335        assert_eq!(header.header_length(), 12);
336
337        header.csrc.push(0xAAAAAAAA);
338        assert_eq!(header.header_length(), 16);
339
340        header.csrc.push(0xBBBBBBBB);
341        assert_eq!(header.header_length(), 20);
342    }
343
344    #[test]
345    fn test_padding_flag() {
346        let mut header = RtpHeader::new(0, 1, 160, 0x12345678);
347        header.padding = true;
348
349        let bytes = header.to_bytes();
350        assert!(bytes[0] & 0x20 != 0);
351
352        let parsed = RtpHeader::parse(&bytes).unwrap();
353        assert!(parsed.padding);
354    }
355
356    #[test]
357    fn test_extension_flag() {
358        let mut header = RtpHeader::new(0, 1, 160, 0x12345678);
359        header.extension = true;
360        // Extension data: 2-byte profile + 2-byte length (0) = 4 bytes
361        header.extension_data = Some(vec![0xBE, 0xDE, 0x00, 0x00]);
362
363        let bytes = header.to_bytes();
364        assert!(bytes[0] & 0x10 != 0);
365
366        let parsed = RtpHeader::parse(&bytes).unwrap();
367        assert!(parsed.extension);
368        assert!(parsed.extension_data.is_some());
369    }
370
371    #[test]
372    fn test_csrc_count_max() {
373        let mut header = RtpHeader::new(0, 1, 160, 0x12345678);
374        // Add 15 CSRCs (max allowed by 4-bit CC field)
375        for i in 0..15 {
376            header.csrc.push(0x11111111 * (i + 1));
377        }
378
379        let bytes = header.to_bytes();
380        let parsed = RtpHeader::parse(&bytes).unwrap();
381        assert_eq!(parsed.csrc.len(), 15);
382    }
383
384    #[test]
385    fn test_truncated_csrc() {
386        // Header claims 2 CSRCs but data is truncated
387        let data = [
388            0x82, 0x00, // V=2, CC=2
389            0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x12, 0x34, 0x56, 0x78,
390            // Only 4 bytes of CSRC instead of 8
391            0xAA, 0xAA, 0xAA, 0xAA,
392        ];
393        assert!(RtpHeader::parse(&data).is_none());
394    }
395
396    #[test]
397    fn test_packet_with_payload() {
398        let payload = vec![0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE];
399        let packet = RtpPacket::simple(0, 1, 160, 0x12345678, payload.clone());
400
401        let bytes = packet.to_bytes();
402        assert_eq!(bytes.len(), 12 + 8);
403
404        let parsed = RtpPacket::parse(&bytes).unwrap();
405        assert_eq!(parsed.payload, payload);
406    }
407
408    #[test]
409    fn test_packet_empty_payload() {
410        let packet = RtpPacket::simple(0, 1, 160, 0x12345678, vec![]);
411        let bytes = packet.to_bytes();
412        assert_eq!(bytes.len(), 12);
413
414        let parsed = RtpPacket::parse(&bytes).unwrap();
415        assert!(parsed.payload.is_empty());
416    }
417
418    #[test]
419    fn test_rtp_packet_new() {
420        let header = RtpHeader::new(8, 100, 16000, 0xABCDEF01);
421        let packet = RtpPacket::new(header.clone(), vec![1, 2, 3]);
422
423        assert_eq!(packet.header.payload_type, 8);
424        assert_eq!(packet.payload, vec![1, 2, 3]);
425    }
426}