use crate::prelude::*;
use crate::xr::rle::{Rle, RleBuilder, RleChunk};
use crate::xr::{XrBlockBuilder, XrBlockParser};
use crate::{RtcpParseError, RtcpWriteError};
use super::XrBlockStaticType;
#[derive(Debug)]
pub struct LossRle<'a> {
rle: Rle<'a>,
}
impl XrBlockStaticType for LossRle<'_> {
const BLOCK_TYPE: u8 = 0x1;
}
impl<'a> XrBlockParser<'a> for LossRle<'a> {
fn parse(data: &'a [u8]) -> Result<Self, RtcpParseError> {
let rle = Rle::parse(data)?;
let ret = Self { rle };
Ok(ret)
}
#[inline(always)]
fn header_data(&self) -> [u8; 4] {
self.rle.block.header_data()
}
}
impl LossRle<'_> {
pub fn thinning(&self) -> u8 {
self.rle.thinning()
}
pub fn media_ssrc(&self) -> u32 {
self.rle.media_ssrc()
}
pub fn begin(&self) -> u16 {
self.rle.begin()
}
pub fn end(&self) -> u16 {
self.rle.end()
}
pub fn sequence_iter(&self) -> impl Iterator<Item = u16> + '_ {
self.rle.sequence_iter()
}
pub fn chunk_iter(&self) -> impl Iterator<Item = RleChunk> + '_ {
self.rle.chunk_iter()
}
pub fn builder() -> LossRleBuilder {
let mut builder = LossRleBuilder {
rle: Rle::builder(),
};
builder.rle = builder.rle.block_type(Self::BLOCK_TYPE);
builder
}
}
#[derive(Debug, Default)]
pub struct LossRleBuilder {
rle: RleBuilder,
}
impl LossRleBuilder {
pub fn ssrc(mut self, ssrc: u32) -> Self {
self.rle = self.rle.ssrc(ssrc);
self
}
pub fn begin(mut self, begin: u16) -> Self {
self.rle = self.rle.begin(begin);
self
}
pub fn end(mut self, end: u16) -> Self {
self.rle = self.rle.end(end);
self
}
pub fn thinning(mut self, thinning: u8) -> Self {
assert!(thinning <= 0xf);
self.rle = self.rle.thinning(thinning);
self
}
pub fn add_chunk(mut self, chunk: RleChunk) -> Self {
self.rle = self.rle.add_chunk(chunk);
self
}
}
impl XrBlockBuilder<'_> for LossRleBuilder {
fn type_specific_byte(&self) -> u8 {
self.rle.type_specific_byte()
}
}
impl RtcpPacketWriter for LossRleBuilder {
fn calculate_size(&self) -> Result<usize, RtcpWriteError> {
self.rle.calculate_size()
}
fn write_into_unchecked(&self, buf: &mut [u8]) -> usize {
self.rle.write_into_unchecked(buf)
}
fn get_padding(&self) -> Option<u8> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn loss_rle_builder_simple() {
let builder = LossRle::builder()
.ssrc(0x1357_9864)
.begin(400)
.end(500)
.thinning(1)
.add_chunk(RleChunk::RunLength(50));
let len = builder.calculate_size().unwrap();
let mut buf = vec![0; len];
builder.write_into_unchecked(&mut buf);
println!("{buf:x?}");
let rle = LossRle::parse(&buf).unwrap();
assert_eq!(rle.media_ssrc(), 0x1357_9864);
assert_eq!(rle.thinning(), 1);
assert_eq!(rle.begin(), 400);
assert_eq!(rle.end(), 500);
let expected = (400..500).filter(|x| x % 2 == 0).collect::<Vec<_>>();
let sequence = rle.sequence_iter().collect::<Vec<_>>();
assert_eq!(sequence, expected);
}
}