Skip to main content

rtp_engine/rtp/
mod.rs

1//! RTP (Real-time Transport Protocol) implementation.
2//!
3//! This module provides packet construction, parsing, and RTCP support
4//! according to RFC 3550.
5//!
6//! # RTP Packet Structure
7//!
8//! ```text
9//!  0                   1                   2                   3
10//!  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
11//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
12//! |V=2|P|X|  CC   |M|     PT      |       sequence number         |
13//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14//! |                           timestamp                           |
15//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16//! |           synchronization source (SSRC) identifier            |
17//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18//! ```
19
20mod header;
21mod rtcp;
22mod stats;
23
24pub use header::{RtpHeader, RtpPacket};
25pub use rtcp::{RtcpPacket, build_rtcp_bye, build_rtcp_rr, build_rtcp_sr};
26pub use stats::{RtpCounters, RtpStats};
27
28/// Parse an RTP packet header and return the payload type and payload data.
29///
30/// Returns `None` if the packet is too short or malformed.
31pub fn parse_rtp(data: &[u8]) -> Option<(RtpHeader, &[u8])> {
32    if data.len() < 12 {
33        return None;
34    }
35
36    let header = RtpHeader::parse(data)?;
37    let payload_offset = header.header_length();
38
39    if payload_offset <= data.len() {
40        Some((header, &data[payload_offset..]))
41    } else {
42        None
43    }
44}
45
46/// Parse just the payload type from an RTP packet.
47pub fn parse_payload_type(data: &[u8]) -> Option<u8> {
48    if data.len() < 2 {
49        return None;
50    }
51    Some(data[1] & 0x7F)
52}
53
54/// Parse the sequence number from an RTP packet.
55pub fn parse_sequence(data: &[u8]) -> Option<u16> {
56    if data.len() < 4 {
57        return None;
58    }
59    Some(u16::from_be_bytes([data[2], data[3]]))
60}
61
62/// Parse the timestamp from an RTP packet.
63pub fn parse_timestamp(data: &[u8]) -> Option<u32> {
64    if data.len() < 8 {
65        return None;
66    }
67    Some(u32::from_be_bytes([data[4], data[5], data[6], data[7]]))
68}
69
70/// Parse the SSRC from an RTP packet.
71pub fn parse_ssrc(data: &[u8]) -> Option<u32> {
72    if data.len() < 12 {
73        return None;
74    }
75    Some(u32::from_be_bytes([data[8], data[9], data[10], data[11]]))
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_parse_rtp() {
84        let packet = [
85            0x80, 0x00, // V=2, PT=0
86            0x00, 0x01, // seq=1
87            0x00, 0x00, 0x00, 0xA0, // timestamp=160
88            0x12, 0x34, 0x56, 0x78, // SSRC
89            0xDE, 0xAD, 0xBE, 0xEF, // payload
90        ];
91
92        let (header, payload) = parse_rtp(&packet).unwrap();
93        assert_eq!(header.payload_type, 0);
94        assert_eq!(header.sequence, 1);
95        assert_eq!(header.timestamp, 160);
96        assert_eq!(header.ssrc, 0x12345678);
97        assert_eq!(payload, &[0xDE, 0xAD, 0xBE, 0xEF]);
98    }
99
100    #[test]
101    fn test_parse_helpers() {
102        let packet = [
103            0x80, 0x08, // V=2, PT=8
104            0x00, 0x0A, // seq=10
105            0x00, 0x00, 0x01, 0x00, // timestamp=256
106            0xAA, 0xBB, 0xCC, 0xDD, // SSRC
107        ];
108
109        assert_eq!(parse_payload_type(&packet), Some(8));
110        assert_eq!(parse_sequence(&packet), Some(10));
111        assert_eq!(parse_timestamp(&packet), Some(256));
112        assert_eq!(parse_ssrc(&packet), Some(0xAABBCCDD));
113    }
114}