mod header;
mod rtcp;
mod stats;
pub use header::{RtpHeader, RtpPacket};
pub use rtcp::{RtcpPacket, build_rtcp_bye, build_rtcp_rr, build_rtcp_sr};
pub use stats::{RtpCounters, RtpStats};
pub fn parse_rtp(data: &[u8]) -> Option<(RtpHeader, &[u8])> {
if data.len() < 12 {
return None;
}
let header = RtpHeader::parse(data)?;
let payload_offset = header.header_length();
if payload_offset <= data.len() {
Some((header, &data[payload_offset..]))
} else {
None
}
}
pub fn parse_payload_type(data: &[u8]) -> Option<u8> {
if data.len() < 2 {
return None;
}
Some(data[1] & 0x7F)
}
pub fn parse_sequence(data: &[u8]) -> Option<u16> {
if data.len() < 4 {
return None;
}
Some(u16::from_be_bytes([data[2], data[3]]))
}
pub fn parse_timestamp(data: &[u8]) -> Option<u32> {
if data.len() < 8 {
return None;
}
Some(u32::from_be_bytes([data[4], data[5], data[6], data[7]]))
}
pub fn parse_ssrc(data: &[u8]) -> Option<u32> {
if data.len() < 12 {
return None;
}
Some(u32::from_be_bytes([data[8], data[9], data[10], data[11]]))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_rtp() {
let packet = [
0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xA0, 0x12, 0x34, 0x56, 0x78, 0xDE, 0xAD, 0xBE, 0xEF, ];
let (header, payload) = parse_rtp(&packet).unwrap();
assert_eq!(header.payload_type, 0);
assert_eq!(header.sequence, 1);
assert_eq!(header.timestamp, 160);
assert_eq!(header.ssrc, 0x12345678);
assert_eq!(payload, &[0xDE, 0xAD, 0xBE, 0xEF]);
}
#[test]
fn test_parse_helpers() {
let packet = [
0x80, 0x08, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0xAA, 0xBB, 0xCC, 0xDD, ];
assert_eq!(parse_payload_type(&packet), Some(8));
assert_eq!(parse_sequence(&packet), Some(10));
assert_eq!(parse_timestamp(&packet), Some(256));
assert_eq!(parse_ssrc(&packet), Some(0xAABBCCDD));
}
}