use std::time::Duration;
use bytes::{Buf, BufMut, Bytes, BytesMut};
use zerocopy::{
byteorder::network_endian::{U32, U64},
FromBytes, Immutable, IntoBytes, KnownLayout, SizeError, Unaligned,
};
use crate::{InvalidInput, RtcpPacket, RtcpPacketType};
#[derive(Copy, Clone, KnownLayout, Immutable, Unaligned, IntoBytes, FromBytes)]
#[repr(C)]
struct RawReportBlock {
ssrc: U32,
loss: U32,
extended_sequence_number: U32,
jitter: U32,
last_sr_timestamp: U32,
delay_since_last_sr: U32,
}
#[derive(Copy, Clone)]
pub struct ReportBlock {
ssrc: u32,
loss: u32,
extended_sequence_number: u32,
jitter: u32,
last_sr_timestamp: u32,
delay_since_last_sr: u32,
}
impl ReportBlock {
pub const RAW_SIZE: usize = std::mem::size_of::<RawReportBlock>();
#[inline]
pub const fn new(ssrc: u32) -> Self {
Self {
ssrc,
loss: 0,
extended_sequence_number: 0,
jitter: 0,
last_sr_timestamp: 0,
delay_since_last_sr: 0,
}
}
pub fn decode(data: &mut Bytes) -> Result<Self, InvalidInput> {
let (raw, _) = RawReportBlock::ref_from_prefix(data)
.map_err(SizeError::from)
.map_err(|_| InvalidInput::new())?;
let res = Self {
ssrc: raw.ssrc.get(),
loss: raw.loss.get(),
extended_sequence_number: raw.extended_sequence_number.get(),
jitter: raw.jitter.get(),
last_sr_timestamp: raw.last_sr_timestamp.get(),
delay_since_last_sr: raw.delay_since_last_sr.get(),
};
data.advance(std::mem::size_of::<RawReportBlock>());
Ok(res)
}
pub fn encode(&self, buf: &mut BytesMut) {
let raw = RawReportBlock {
ssrc: U32::new(self.ssrc),
loss: U32::new(self.loss),
extended_sequence_number: U32::new(self.extended_sequence_number),
jitter: U32::new(self.jitter),
last_sr_timestamp: U32::new(self.last_sr_timestamp),
delay_since_last_sr: U32::new(self.delay_since_last_sr),
};
buf.extend_from_slice(raw.as_bytes());
}
#[inline]
pub fn ssrc(&self) -> u32 {
self.ssrc
}
#[inline]
pub fn with_ssrc(mut self, ssrc: u32) -> Self {
self.ssrc = ssrc;
self
}
#[inline]
pub fn fractional_loss(&self) -> u8 {
(self.loss >> 24) as u8
}
#[inline]
pub fn with_fractional_loss(mut self, loss: u8) -> Self {
self.loss &= 0x00ffffff;
self.loss |= (loss as u32) << 24;
self
}
#[inline]
pub fn cumulative_loss(&self) -> i32 {
((self.loss << 8) as i32) >> 8
}
#[inline]
pub fn with_cumulative_loss(mut self, loss: i32) -> Self {
let min = -(1i32 << 23);
let max = (1i32 << 23) - 1;
let loss = loss.clamp(min, max) as u32;
self.loss &= 0xff000000;
self.loss |= loss & 0x00ffffff;
self
}
pub fn with_loss(self, expected: u64, received: u64) -> Self {
let delta = expected as i64 - received as i64;
let fraction = if delta < 0 {
0
} else {
((delta as u64) << 8) / expected
};
self.with_fractional_loss(fraction as u8)
.with_cumulative_loss(delta as i32)
}
#[inline]
pub fn extended_sequence_number(&self) -> u32 {
self.extended_sequence_number
}
#[inline]
pub fn with_extended_sequence_number(mut self, n: u32) -> Self {
self.extended_sequence_number = n;
self
}
#[inline]
pub fn jitter(&self) -> u32 {
self.jitter
}
#[inline]
pub fn with_jitter(mut self, jitter: u32) -> Self {
self.jitter = jitter;
self
}
#[inline]
pub fn last_sr_timestamp(&self) -> u64 {
(self.last_sr_timestamp as u64) << 16
}
#[inline]
pub fn with_last_sr_timestamp(mut self, ts: u64) -> Self {
self.last_sr_timestamp = (ts >> 16) as u32;
self
}
#[inline]
pub fn delay_since_last_sr(&self) -> Duration {
let secs = (self.delay_since_last_sr >> 16) as u64;
let nanos = ((self.delay_since_last_sr & 0xffff) as u64 * 1_000_000_000) >> 16;
Duration::new(secs, nanos as u32)
}
#[inline]
pub fn with_delay_since_last_sr(mut self, delay: Duration) -> Self {
let secs = (delay.as_secs() << 16) as u32;
let fraction = (((delay.subsec_nanos() as u64) << 16) / 1_000_000_000) as u32;
self.delay_since_last_sr = secs + fraction;
self
}
#[inline]
pub fn raw_size(&self) -> usize {
Self::RAW_SIZE
}
}
#[derive(Copy, Clone, KnownLayout, Immutable, Unaligned, IntoBytes, FromBytes)]
#[repr(C)]
struct RawSenderReportHeader {
sender_ssrc: U32,
ntp_timestamp: U64,
rtp_timestamp: U32,
packet_count: U32,
octet_count: U32,
}
#[derive(Clone)]
pub struct SenderReport {
sender_ssrc: u32,
ntp_timestamp: u64,
rtp_timestamp: u32,
packet_count: u32,
octet_count: u32,
report_blocks: Vec<ReportBlock>,
}
impl SenderReport {
#[inline]
pub const fn new(sender_ssrc: u32) -> Self {
Self {
sender_ssrc,
ntp_timestamp: 0,
rtp_timestamp: 0,
packet_count: 0,
octet_count: 0,
report_blocks: Vec::new(),
}
}
pub fn decode(packet: &RtcpPacket) -> Result<Self, InvalidInput> {
let header = packet.header();
let mut data = packet.stripped_payload();
let (raw, _) = RawSenderReportHeader::ref_from_prefix(&data)
.map_err(SizeError::from)
.map_err(|_| InvalidInput::new())?;
let mut res = Self {
sender_ssrc: raw.sender_ssrc.get(),
ntp_timestamp: raw.ntp_timestamp.get(),
rtp_timestamp: raw.rtp_timestamp.get(),
packet_count: raw.packet_count.get(),
octet_count: raw.octet_count.get(),
report_blocks: Vec::with_capacity(header.item_count() as usize),
};
data.advance(std::mem::size_of::<RawSenderReportHeader>());
for _ in 0..header.item_count() {
res.report_blocks.push(ReportBlock::decode(&mut data)?);
}
Ok(res)
}
pub fn encode(&self) -> RtcpPacket {
let mut payload = BytesMut::with_capacity(self.raw_size());
let raw = RawSenderReportHeader {
sender_ssrc: U32::new(self.sender_ssrc),
ntp_timestamp: U64::new(self.ntp_timestamp),
rtp_timestamp: U32::new(self.rtp_timestamp),
packet_count: U32::new(self.packet_count),
octet_count: U32::new(self.octet_count),
};
payload.extend_from_slice(raw.as_bytes());
for block in &self.report_blocks {
block.encode(&mut payload);
}
RtcpPacket::new(RtcpPacketType::SR)
.with_item_count(self.report_blocks.len() as u8)
.with_payload(payload.freeze(), 0)
}
#[inline]
pub fn sender_ssrc(&self) -> u32 {
self.sender_ssrc
}
#[inline]
pub fn with_sender_ssrc(mut self, ssrc: u32) -> Self {
self.sender_ssrc = ssrc;
self
}
#[inline]
pub fn ntp_timestamp(&self) -> u64 {
self.ntp_timestamp
}
#[inline]
pub fn with_ntp_timestamp(mut self, timestamp: u64) -> Self {
self.ntp_timestamp = timestamp;
self
}
#[inline]
pub fn rtp_timestamp(&self) -> u32 {
self.rtp_timestamp
}
#[inline]
pub fn with_rtp_timestamp(mut self, timestamp: u32) -> Self {
self.rtp_timestamp = timestamp;
self
}
#[inline]
pub fn packet_count(&self) -> u32 {
self.packet_count
}
#[inline]
pub fn with_packet_count(mut self, count: u32) -> Self {
self.packet_count = count;
self
}
#[inline]
pub fn octet_count(&self) -> u32 {
self.octet_count
}
#[inline]
pub fn with_octet_count(mut self, count: u32) -> Self {
self.octet_count = count;
self
}
#[inline]
pub fn report_blocks(&self) -> &[ReportBlock] {
&self.report_blocks
}
#[inline]
pub fn with_report_blocks<T>(mut self, blocks: T) -> Self
where
T: Into<Vec<ReportBlock>>,
{
let blocks = blocks.into();
assert!(blocks.len() < 32);
self.report_blocks = blocks;
self
}
#[inline]
pub fn raw_size(&self) -> usize {
std::mem::size_of::<RawSenderReportHeader>()
+ std::mem::size_of::<RawReportBlock>() * self.report_blocks.len()
}
}
#[derive(Clone)]
pub struct ReceiverReport {
sender_ssrc: u32,
report_blocks: Vec<ReportBlock>,
}
impl ReceiverReport {
#[inline]
pub const fn new(sender_ssrc: u32) -> Self {
Self {
sender_ssrc,
report_blocks: Vec::new(),
}
}
pub fn decode(packet: &RtcpPacket) -> Result<Self, InvalidInput> {
let header = packet.header();
let mut data = packet.stripped_payload();
if data.len() < 4 {
return Err(InvalidInput::new());
}
let mut res = Self {
sender_ssrc: data.get_u32(),
report_blocks: Vec::with_capacity(header.item_count() as usize),
};
for _ in 0..header.item_count() {
res.report_blocks.push(ReportBlock::decode(&mut data)?);
}
Ok(res)
}
pub fn encode(&self) -> RtcpPacket {
let mut payload = BytesMut::with_capacity(self.raw_size());
payload.put_u32(self.sender_ssrc);
for block in &self.report_blocks {
block.encode(&mut payload);
}
RtcpPacket::new(RtcpPacketType::RR)
.with_item_count(self.report_blocks.len() as u8)
.with_payload(payload.freeze(), 0)
}
#[inline]
pub fn sender_ssrc(&self) -> u32 {
self.sender_ssrc
}
#[inline]
pub fn with_sender_ssrc(mut self, ssrc: u32) -> Self {
self.sender_ssrc = ssrc;
self
}
#[inline]
pub fn report_blocks(&self) -> &[ReportBlock] {
&self.report_blocks
}
#[inline]
pub fn with_report_blocks<T>(mut self, blocks: T) -> Self
where
T: Into<Vec<ReportBlock>>,
{
let blocks = blocks.into();
assert!(blocks.len() < 32);
self.report_blocks = blocks;
self
}
#[inline]
pub fn raw_size(&self) -> usize {
4 + std::mem::size_of::<RawReportBlock>() * self.report_blocks.len()
}
}