use super::*;
const RLE_REPORT_BLOCK_MIN_LENGTH: u16 = 8;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ChunkType {
RunLength = 0,
BitVector = 1,
TerminatingNull = 2,
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct Chunk(pub u16);
impl fmt::Display for Chunk {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.chunk_type() {
ChunkType::RunLength => {
let run_type = self.run_type().unwrap_or(0);
write!(f, "[RunLength type={}, length={}]", run_type, self.value())
}
ChunkType::BitVector => write!(f, "[BitVector {:#b}", self.value()),
ChunkType::TerminatingNull => write!(f, "[TerminatingNull]"),
}
}
}
impl Chunk {
pub fn chunk_type(&self) -> ChunkType {
if self.0 == 0 {
ChunkType::TerminatingNull
} else if (self.0 >> 15) == 0 {
ChunkType::RunLength
} else {
ChunkType::BitVector
}
}
pub fn run_type(&self) -> error::Result<u8> {
if self.chunk_type() != ChunkType::RunLength {
Err(error::Error::WrongChunkType)
} else {
Ok((self.0 >> 14) as u8 & 0x01)
}
}
pub fn value(&self) -> u16 {
match self.chunk_type() {
ChunkType::RunLength => self.0 & 0x3FFF,
ChunkType::BitVector => self.0 & 0x7FFF,
ChunkType::TerminatingNull => 0,
}
}
}
#[derive(Debug, Default, PartialEq, Eq, Clone)]
pub struct RLEReportBlock {
pub is_loss_rle: bool,
pub t: u8,
pub ssrc: u32,
pub begin_seq: u16,
pub end_seq: u16,
pub chunks: Vec<Chunk>,
}
pub type LossRLEReportBlock = RLEReportBlock;
pub type DuplicateRLEReportBlock = RLEReportBlock;
impl RLEReportBlock {
pub fn xr_header(&self) -> XRHeader {
XRHeader {
block_type: if self.is_loss_rle {
BlockType::LossRLE
} else {
BlockType::DuplicateRLE
},
type_specific: self.t & 0x0F,
block_length: (self.raw_size() / 4 - 1) as u16,
}
}
}
impl fmt::Display for RLEReportBlock {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl Packet for RLEReportBlock {
fn header(&self) -> Header {
Header::default()
}
fn destination_ssrc(&self) -> Vec<u32> {
vec![self.ssrc]
}
fn raw_size(&self) -> usize {
XR_HEADER_LENGTH + RLE_REPORT_BLOCK_MIN_LENGTH as usize + self.chunks.len() * 2
}
fn as_any(&self) -> &(dyn Any + Send + Sync) {
self
}
fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool {
other.as_any().downcast_ref::<RLEReportBlock>() == Some(self)
}
fn cloned(&self) -> Box<dyn Packet + Send + Sync> {
Box::new(self.clone())
}
}
impl MarshalSize for RLEReportBlock {
fn marshal_size(&self) -> usize {
self.raw_size()
}
}
impl Marshal for RLEReportBlock {
fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
if buf.remaining_mut() < self.marshal_size() {
return Err(error::Error::BufferTooShort.into());
}
let h = self.xr_header();
let n = h.marshal_to(buf)?;
buf = &mut buf[n..];
buf.put_u32(self.ssrc);
buf.put_u16(self.begin_seq);
buf.put_u16(self.end_seq);
for chunk in &self.chunks {
buf.put_u16(chunk.0);
}
Ok(self.marshal_size())
}
}
impl Unmarshal for RLEReportBlock {
fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
where
Self: Sized,
B: Buf,
{
if raw_packet.remaining() < XR_HEADER_LENGTH {
return Err(error::Error::PacketTooShort.into());
}
let xr_header = XRHeader::unmarshal(raw_packet)?;
let block_length = match xr_header.block_length.checked_mul(4) {
Some(length) => length,
None => return Err(error::Error::InvalidBlockSize.into()),
};
if block_length < RLE_REPORT_BLOCK_MIN_LENGTH
|| !(block_length - RLE_REPORT_BLOCK_MIN_LENGTH).is_multiple_of(2)
|| raw_packet.remaining() < block_length as usize
{
return Err(error::Error::PacketTooShort.into());
}
let is_loss_rle = xr_header.block_type == BlockType::LossRLE;
let t = xr_header.type_specific & 0x0F;
let ssrc = raw_packet.get_u32();
let begin_seq = raw_packet.get_u16();
let end_seq = raw_packet.get_u16();
let remaining = block_length - RLE_REPORT_BLOCK_MIN_LENGTH;
let mut chunks = vec![];
for _ in 0..remaining / 2 {
chunks.push(Chunk(raw_packet.get_u16()));
}
Ok(RLEReportBlock {
is_loss_rle,
t,
ssrc,
begin_seq,
end_seq,
chunks,
})
}
}