#[cfg(test)]
use super::header::RTP_MIN_HEADER_SIZE;
use bytes::{Bytes, BytesMut};
use std::fmt;
use tracing::debug;
use super::header::RtpHeader;
use crate::{Result, RtpSequenceNumber, RtpSsrc, RtpTimestamp};
#[derive(Clone, PartialEq, Eq)]
pub struct RtpPacket {
pub header: RtpHeader,
pub payload: Bytes,
}
impl RtpPacket {
pub fn new(header: RtpHeader, payload: Bytes) -> Self {
Self { header, payload }
}
pub fn new_with_payload(
payload_type: u8,
sequence_number: RtpSequenceNumber,
timestamp: RtpTimestamp,
ssrc: RtpSsrc,
payload: Bytes,
) -> Self {
let header = RtpHeader::new(payload_type, sequence_number, timestamp, ssrc);
Self { header, payload }
}
pub fn size(&self) -> usize {
self.header.size() + self.payload.len()
}
pub fn parse(data: &[u8]) -> Result<Self> {
debug!("Parsing RTP packet from {} bytes", data.len());
let (header, header_size) = RtpHeader::parse_without_consuming(data)?;
debug!("Parsed header of size {}", header_size);
let payload = if data.len() > header_size {
Bytes::copy_from_slice(&data[header_size..])
} else {
Bytes::new()
};
debug!("Extracted payload of size {}", payload.len());
Ok(Self { header, payload })
}
pub fn parse_from_bytes(data: Bytes) -> Result<Self> {
debug!("Parsing RTP packet from {} bytes (zero-copy)", data.len());
let (header, header_size) = RtpHeader::parse_without_consuming(&data)?;
debug!("Parsed header of size {}", header_size);
let payload = if data.len() > header_size {
data.slice(header_size..)
} else {
Bytes::new()
};
debug!("Sliced payload of size {}", payload.len());
Ok(Self { header, payload })
}
pub fn serialize(&self) -> Result<Bytes> {
let total_size = self.size();
let mut buf = BytesMut::with_capacity(total_size);
self.header.serialize(&mut buf)?;
buf.extend_from_slice(&self.payload);
Ok(buf.freeze())
}
pub fn serialize_into(&self, buf: &mut BytesMut) -> Result<Bytes> {
let total_size = self.size();
buf.reserve(total_size);
self.header.serialize(buf)?;
buf.extend_from_slice(&self.payload);
Ok(buf.split().freeze())
}
}
impl fmt::Debug for RtpPacket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"RtpPacket {{ header: {:?}, payload_len: {} }}",
self.header,
self.payload.len()
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use bytes::Bytes;
#[test]
fn test_new_with_payload() {
let payload = Bytes::from_static(b"test payload");
let packet = RtpPacket::new_with_payload(
96, 1000, 12345, 0xabcdef01, payload.clone(),
);
assert_eq!(packet.header.payload_type, 96);
assert_eq!(packet.header.sequence_number, 1000);
assert_eq!(packet.header.timestamp, 12345);
assert_eq!(packet.header.ssrc, 0xabcdef01);
assert_eq!(packet.payload, payload);
}
#[test]
fn test_size() {
let payload = Bytes::from_static(b"test payload");
let packet = RtpPacket::new_with_payload(96, 1000, 12345, 0xabcdef01, payload);
assert_eq!(packet.size(), RTP_MIN_HEADER_SIZE + 12); }
#[test]
fn test_serialize_parse_roundtrip() {
let payload = Bytes::from_static(b"test payload data");
let original = RtpPacket::new_with_payload(96, 1000, 12345, 0xabcdef01, payload);
let serialized = original.serialize().unwrap();
let parsed = RtpPacket::parse(&serialized).unwrap();
assert_eq!(parsed.header.payload_type, original.header.payload_type);
assert_eq!(
parsed.header.sequence_number,
original.header.sequence_number
);
assert_eq!(parsed.header.timestamp, original.header.timestamp);
assert_eq!(parsed.header.ssrc, original.header.ssrc);
assert_eq!(parsed.payload, original.payload);
}
#[test]
fn test_parse_from_bytes_matches_slice_parse() {
let payload = Bytes::from_static(b"test payload data");
let original = RtpPacket::new_with_payload(96, 1000, 12345, 0xabcdef01, payload);
let serialized = original.serialize().unwrap();
let parsed_from_slice = RtpPacket::parse(&serialized).unwrap();
let parsed_from_bytes = RtpPacket::parse_from_bytes(serialized).unwrap();
assert_eq!(parsed_from_bytes, parsed_from_slice);
}
#[test]
fn test_serialize_into_writes_one_payload() {
let payload = Bytes::from_static(b"abc123");
let packet = RtpPacket::new_with_payload(96, 1000, 12345, 0xabcdef01, payload.clone());
let mut reusable = BytesMut::with_capacity(1500);
let serialized = packet.serialize_into(&mut reusable).unwrap();
assert_eq!(serialized.len(), RTP_MIN_HEADER_SIZE + payload.len());
assert_eq!(&serialized[RTP_MIN_HEADER_SIZE..], payload.as_ref());
}
#[test]
fn test_debug_format() {
let packet = RtpPacket::new_with_payload(
96,
1000,
12345,
0xabcdef01,
Bytes::from_static(b"test payload"),
);
let debug_str = format!("{:?}", packet);
assert!(debug_str.contains("payload_len: 12"));
assert!(debug_str.contains("header:"));
}
}