1mod 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
28pub 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
46pub fn parse_payload_type(data: &[u8]) -> Option<u8> {
48 if data.len() < 2 {
49 return None;
50 }
51 Some(data[1] & 0x7F)
52}
53
54pub 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
62pub 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
70pub 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, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x12, 0x34, 0x56, 0x78, 0xDE, 0xAD, 0xBE, 0xEF, ];
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, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, ];
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}