#[cfg(test)]
mod compound_packet_test;
use crate::{
error::Error, header::*, packet::*, receiver_report::*, sender_report::*,
source_description::*, util::*,
};
use util::marshal::{Marshal, MarshalSize, Unmarshal};
use anyhow::Result;
use bytes::{Buf, Bytes};
use std::any::Any;
use std::fmt;
#[derive(Debug, Default, PartialEq, Clone)]
pub struct CompoundPacket(pub Vec<Box<dyn Packet>>);
impl fmt::Display for CompoundPacket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}
impl Packet for CompoundPacket {
fn header(&self) -> Header {
Header::default()
}
fn destination_ssrc(&self) -> Vec<u32> {
if self.0.is_empty() {
vec![]
} else {
self.0[0].destination_ssrc()
}
}
fn raw_size(&self) -> usize {
let mut l = 0;
for packet in &self.0 {
l += packet.marshal_size();
}
l
}
fn as_any(&self) -> &dyn Any {
self
}
fn equal(&self, other: &dyn Packet) -> bool {
other
.as_any()
.downcast_ref::<CompoundPacket>()
.map_or(false, |a| self == a)
}
fn cloned(&self) -> Box<dyn Packet> {
Box::new(self.clone())
}
}
impl MarshalSize for CompoundPacket {
fn marshal_size(&self) -> usize {
let l = self.raw_size();
l + get_padding_size(l)
}
}
impl Marshal for CompoundPacket {
fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
self.validate()?;
for packet in &self.0 {
let n = packet.marshal_to(buf)?;
buf = &mut buf[n..];
}
Ok(self.marshal_size())
}
}
impl Unmarshal for CompoundPacket {
fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
where
Self: Sized,
B: Buf,
{
let mut packets = vec![];
while raw_packet.has_remaining() {
let p = unmarshaller(raw_packet)?;
packets.push(p);
}
let c = CompoundPacket(packets);
c.validate()?;
Ok(c)
}
}
impl CompoundPacket {
pub fn validate(&self) -> Result<()> {
if self.0.is_empty() {
return Err(Error::EmptyCompound.into());
}
if self.0[0].as_any().downcast_ref::<SenderReport>().is_none()
&& self.0[0]
.as_any()
.downcast_ref::<ReceiverReport>()
.is_none()
{
return Err(Error::BadFirstPacket.into());
}
for pkt in &self.0[1..] {
if pkt.as_any().downcast_ref::<ReceiverReport>().is_some() {
continue;
} else if let Some(e) = pkt.as_any().downcast_ref::<SourceDescription>() {
let mut has_cname = false;
for c in &e.chunks {
for it in &c.items {
if it.sdes_type == SdesType::SdesCname {
has_cname = true
}
}
}
if !has_cname {
return Err(Error::MissingCname.into());
}
return Ok(());
} else {
return Err(Error::PacketBeforeCname.into());
}
}
Err(Error::MissingCname.into())
}
pub fn cname(&self) -> Result<Bytes> {
if self.0.is_empty() {
return Err(Error::EmptyCompound.into());
}
for pkt in &self.0[1..] {
if let Some(sdes) = pkt.as_any().downcast_ref::<SourceDescription>() {
for c in &sdes.chunks {
for it in &c.items {
if it.sdes_type == SdesType::SdesCname {
return Ok(it.text.clone());
}
}
}
} else if pkt.as_any().downcast_ref::<ReceiverReport>().is_none() {
return Err(Error::PacketBeforeCname.into());
}
}
Err(Error::MissingCname.into())
}
}