1 #[cfg(test)] 2 mod compound_packet_test; 3 4 use crate::{ 5 error::Error, header::*, packet::*, receiver_report::*, sender_report::*, 6 source_description::*, util::*, 7 }; 8 use util::marshal::{Marshal, MarshalSize, Unmarshal}; 9 10 use bytes::{Buf, Bytes}; 11 use std::any::Any; 12 use std::fmt; 13 14 type Result<T> = std::result::Result<T, util::Error>; 15 16 /// A CompoundPacket is a collection of RTCP packets transmitted as a single packet with 17 /// the underlying protocol (for example UDP). 18 /// 19 /// To maximize the resolution of receiption statistics, the first Packet in a CompoundPacket 20 /// must always be either a SenderReport or a ReceiverReport. This is true even if no data 21 /// has been sent or received, in which case an empty ReceiverReport must be sent, and even 22 /// if the only other RTCP packet in the compound packet is a Goodbye. 23 /// 24 /// Next, a SourceDescription containing a CNAME item must be included in each CompoundPacket 25 /// to identify the source and to begin associating media for purposes such as lip-sync. 26 /// 27 /// Other RTCP packet types may follow in any order. Packet types may appear more than once. 28 #[derive(Debug, Default, PartialEq, Clone)] 29 pub struct CompoundPacket(pub Vec<Box<dyn Packet + Send + Sync>>); 30 31 impl fmt::Display for CompoundPacket { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 33 write!(f, "{self:?}") 34 } 35 } 36 37 impl Packet for CompoundPacket { header(&self) -> Header38 fn header(&self) -> Header { 39 Header::default() 40 } 41 42 /// destination_ssrc returns the synchronization sources associated with this 43 /// CompoundPacket's reception report. destination_ssrc(&self) -> Vec<u32>44 fn destination_ssrc(&self) -> Vec<u32> { 45 if self.0.is_empty() { 46 vec![] 47 } else { 48 self.0[0].destination_ssrc() 49 } 50 } 51 raw_size(&self) -> usize52 fn raw_size(&self) -> usize { 53 let mut l = 0; 54 for packet in &self.0 { 55 l += packet.marshal_size(); 56 } 57 l 58 } 59 as_any(&self) -> &(dyn Any + Send + Sync)60 fn as_any(&self) -> &(dyn Any + Send + Sync) { 61 self 62 } 63 equal(&self, other: &(dyn Packet + Send + Sync)) -> bool64 fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool { 65 other 66 .as_any() 67 .downcast_ref::<CompoundPacket>() 68 .map_or(false, |a| self == a) 69 } 70 cloned(&self) -> Box<dyn Packet + Send + Sync>71 fn cloned(&self) -> Box<dyn Packet + Send + Sync> { 72 Box::new(self.clone()) 73 } 74 } 75 76 impl MarshalSize for CompoundPacket { marshal_size(&self) -> usize77 fn marshal_size(&self) -> usize { 78 let l = self.raw_size(); 79 // align to 32-bit boundary 80 l + get_padding_size(l) 81 } 82 } 83 84 impl Marshal for CompoundPacket { 85 /// Marshal encodes the CompoundPacket as binary. marshal_to(&self, mut buf: &mut [u8]) -> Result<usize>86 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> { 87 self.validate()?; 88 89 for packet in &self.0 { 90 let n = packet.marshal_to(buf)?; 91 buf = &mut buf[n..]; 92 } 93 94 Ok(self.marshal_size()) 95 } 96 } 97 98 impl Unmarshal for CompoundPacket { unmarshal<B>(raw_packet: &mut B) -> Result<Self> where Self: Sized, B: Buf,99 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self> 100 where 101 Self: Sized, 102 B: Buf, 103 { 104 let mut packets = vec![]; 105 106 while raw_packet.has_remaining() { 107 let p = unmarshaller(raw_packet)?; 108 packets.push(p); 109 } 110 111 let c = CompoundPacket(packets); 112 c.validate()?; 113 114 Ok(c) 115 } 116 } 117 118 impl CompoundPacket { 119 /// Validate returns an error if this is not an RFC-compliant CompoundPacket. validate(&self) -> Result<()>120 pub fn validate(&self) -> Result<()> { 121 if self.0.is_empty() { 122 return Err(Error::EmptyCompound.into()); 123 } 124 125 // SenderReport and ReceiverReport are the only types that 126 // are allowed to be the first packet in a compound datagram 127 if self.0[0].as_any().downcast_ref::<SenderReport>().is_none() 128 && self.0[0] 129 .as_any() 130 .downcast_ref::<ReceiverReport>() 131 .is_none() 132 { 133 return Err(Error::BadFirstPacket.into()); 134 } 135 136 for pkt in &self.0[1..] { 137 // If the number of RecetpionReports exceeds 31 additional ReceiverReports 138 // can be included here. 139 if pkt.as_any().downcast_ref::<ReceiverReport>().is_some() { 140 continue; 141 // A SourceDescription containing a CNAME must be included in every 142 // CompoundPacket. 143 } else if let Some(e) = pkt.as_any().downcast_ref::<SourceDescription>() { 144 let mut has_cname = false; 145 for c in &e.chunks { 146 for it in &c.items { 147 if it.sdes_type == SdesType::SdesCname { 148 has_cname = true 149 } 150 } 151 } 152 153 if !has_cname { 154 return Err(Error::MissingCname.into()); 155 } 156 157 return Ok(()); 158 159 // Other packets are not permitted before the CNAME 160 } else { 161 return Err(Error::PacketBeforeCname.into()); 162 } 163 } 164 165 // CNAME never reached 166 Err(Error::MissingCname.into()) 167 } 168 169 /// CNAME returns the CNAME that *must* be present in every CompoundPacket cname(&self) -> Result<Bytes>170 pub fn cname(&self) -> Result<Bytes> { 171 if self.0.is_empty() { 172 return Err(Error::EmptyCompound.into()); 173 } 174 175 for pkt in &self.0[1..] { 176 if let Some(sdes) = pkt.as_any().downcast_ref::<SourceDescription>() { 177 for c in &sdes.chunks { 178 for it in &c.items { 179 if it.sdes_type == SdesType::SdesCname { 180 return Ok(it.text.clone()); 181 } 182 } 183 } 184 } else if pkt.as_any().downcast_ref::<ReceiverReport>().is_none() { 185 return Err(Error::PacketBeforeCname.into()); 186 } 187 } 188 189 Err(Error::MissingCname.into()) 190 } 191 } 192