use bytes::{Bytes, BytesMut};
use std::fmt;
use tracing::debug;
use crate::error::Error;
use crate::{Result, RtpSequenceNumber, RtpSsrc, RtpTimestamp};
use super::header::{RtpHeader, hex_dump, RTP_MIN_HEADER_SIZE};
#[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 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())
}
}
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_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:"));
}
}