xref: /webrtc/rtcp/src/compound_packet/mod.rs (revision 5d8fe953)
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