xref: /webrtc/rtcp/src/extended_report/mod.rs (revision 7ceeeeb0)
1 #[cfg(test)]
2 mod extended_report_test;
3 
4 pub mod dlrr;
5 pub mod prt;
6 pub mod rle;
7 pub mod rrt;
8 pub mod ssr;
9 pub mod unknown;
10 pub mod vm;
11 
12 pub use dlrr::{DLRRReport, DLRRReportBlock};
13 pub use prt::PacketReceiptTimesReportBlock;
14 pub use rle::{Chunk, ChunkType, DuplicateRLEReportBlock, LossRLEReportBlock, RLEReportBlock};
15 pub use rrt::ReceiverReferenceTimeReportBlock;
16 pub use ssr::{StatisticsSummaryReportBlock, TTLorHopLimitType};
17 pub use unknown::UnknownReportBlock;
18 pub use vm::VoIPMetricsReportBlock;
19 
20 use crate::error;
21 use crate::header::{Header, PacketType, HEADER_LENGTH, SSRC_LENGTH};
22 use crate::packet::Packet;
23 use crate::util::{get_padding_size, put_padding};
24 use bytes::{Buf, BufMut, Bytes};
25 use std::any::Any;
26 use std::fmt;
27 use util::marshal::{Marshal, MarshalSize, Unmarshal};
28 
29 type Result<T> = std::result::Result<T, util::Error>;
30 
31 const XR_HEADER_LENGTH: usize = 4;
32 
33 /// BlockType specifies the type of report in a report block
34 /// Extended Report block types from RFC 3611.
35 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
36 pub enum BlockType {
37     Unknown = 0,
38     LossRLE = 1,               // RFC 3611, section 4.1
39     DuplicateRLE = 2,          // RFC 3611, section 4.2
40     PacketReceiptTimes = 3,    // RFC 3611, section 4.3
41     ReceiverReferenceTime = 4, // RFC 3611, section 4.4
42     DLRR = 5,                  // RFC 3611, section 4.5
43     StatisticsSummary = 6,     // RFC 3611, section 4.6
44     VoIPMetrics = 7,           // RFC 3611, section 4.7
45 }
46 
47 impl Default for BlockType {
48     fn default() -> Self {
49         BlockType::Unknown
50     }
51 }
52 
53 impl From<u8> for BlockType {
54     fn from(v: u8) -> Self {
55         match v {
56             1 => BlockType::LossRLE,
57             2 => BlockType::DuplicateRLE,
58             3 => BlockType::PacketReceiptTimes,
59             4 => BlockType::ReceiverReferenceTime,
60             5 => BlockType::DLRR,
61             6 => BlockType::StatisticsSummary,
62             7 => BlockType::VoIPMetrics,
63             _ => BlockType::Unknown,
64         }
65     }
66 }
67 
68 /// converts the Extended report block types into readable strings
69 impl fmt::Display for BlockType {
70     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71         let s = match *self {
72             BlockType::LossRLE => "LossRLEReportBlockType",
73             BlockType::DuplicateRLE => "DuplicateRLEReportBlockType",
74             BlockType::PacketReceiptTimes => "PacketReceiptTimesReportBlockType",
75             BlockType::ReceiverReferenceTime => "ReceiverReferenceTimeReportBlockType",
76             BlockType::DLRR => "DLRRReportBlockType",
77             BlockType::StatisticsSummary => "StatisticsSummaryReportBlockType",
78             BlockType::VoIPMetrics => "VoIPMetricsReportBlockType",
79             _ => "UnknownReportBlockType",
80         };
81         write!(f, "{}", s)
82     }
83 }
84 
85 /// TypeSpecificField as described in RFC 3611 section 4.5. In typical
86 /// cases, users of ExtendedReports shouldn't need to access this,
87 /// and should instead use the corresponding fields in the actual
88 /// report blocks themselves.
89 pub type TypeSpecificField = u8;
90 
91 /// XRHeader defines the common fields that must appear at the start
92 /// of each report block. In typical cases, users of ExtendedReports
93 /// shouldn't need to access this. For locally-constructed report
94 /// blocks, these values will not be accurate until the corresponding
95 /// packet is marshaled.
96 #[derive(Debug, Default, PartialEq, Eq, Clone)]
97 pub struct XRHeader {
98     pub block_type: BlockType,
99     pub type_specific: TypeSpecificField,
100     pub block_length: u16,
101 }
102 
103 impl MarshalSize for XRHeader {
104     fn marshal_size(&self) -> usize {
105         XR_HEADER_LENGTH
106     }
107 }
108 
109 impl Marshal for XRHeader {
110     /// marshal_to encodes the ExtendedReport in binary
111     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
112         if buf.remaining_mut() < XR_HEADER_LENGTH {
113             return Err(error::Error::BufferTooShort.into());
114         }
115 
116         buf.put_u8(self.block_type as u8);
117         buf.put_u8(self.type_specific);
118         buf.put_u16(self.block_length);
119 
120         Ok(XR_HEADER_LENGTH)
121     }
122 }
123 
124 impl Unmarshal for XRHeader {
125     /// Unmarshal decodes the ExtendedReport from binary
126     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
127     where
128         Self: Sized,
129         B: Buf,
130     {
131         if raw_packet.remaining() < XR_HEADER_LENGTH {
132             return Err(error::Error::PacketTooShort.into());
133         }
134 
135         let block_type: BlockType = raw_packet.get_u8().into();
136         let type_specific = raw_packet.get_u8();
137         let block_length = raw_packet.get_u16();
138 
139         Ok(XRHeader {
140             block_type,
141             type_specific,
142             block_length,
143         })
144     }
145 }
146 /// The ExtendedReport packet is an Implementation of RTCP Extended
147 /// reports defined in RFC 3611. It is used to convey detailed
148 /// information about an RTP stream. Each packet contains one or
149 /// more report blocks, each of which conveys a different kind of
150 /// information.
151 ///
152 ///  0                   1                   2                   3
153 ///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
154 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155 /// |V=2|P|reserved |   PT=XR=207   |             length            |
156 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157 /// |                              ssrc                             |
158 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159 /// :                         report blocks                         :
160 /// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
161 #[derive(Debug, PartialEq, Default, Clone)]
162 pub struct ExtendedReport {
163     pub sender_ssrc: u32,
164     pub reports: Vec<Box<dyn Packet + Send + Sync>>,
165 }
166 
167 impl fmt::Display for ExtendedReport {
168     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169         write!(f, "{:?}", self)
170     }
171 }
172 
173 impl Packet for ExtendedReport {
174     /// Header returns the Header associated with this packet.
175     fn header(&self) -> Header {
176         Header {
177             padding: get_padding_size(self.raw_size()) != 0,
178             count: 0,
179             packet_type: PacketType::ExtendedReport,
180             length: ((self.marshal_size() / 4) - 1) as u16,
181         }
182     }
183 
184     /// destination_ssrc returns an array of ssrc values that this packet refers to.
185     fn destination_ssrc(&self) -> Vec<u32> {
186         let mut ssrc = vec![];
187         for p in &self.reports {
188             ssrc.extend(p.destination_ssrc());
189         }
190         ssrc
191     }
192 
193     fn raw_size(&self) -> usize {
194         let mut reps_length = 0;
195         for rep in &self.reports {
196             reps_length += rep.marshal_size();
197         }
198         HEADER_LENGTH + SSRC_LENGTH + reps_length
199     }
200 
201     fn as_any(&self) -> &(dyn Any + Send + Sync) {
202         self
203     }
204 
205     fn equal(&self, other: &(dyn Packet + Send + Sync)) -> bool {
206         other
207             .as_any()
208             .downcast_ref::<ExtendedReport>()
209             .map_or(false, |a| self == a)
210     }
211 
212     fn cloned(&self) -> Box<dyn Packet + Send + Sync> {
213         Box::new(self.clone())
214     }
215 }
216 
217 impl MarshalSize for ExtendedReport {
218     fn marshal_size(&self) -> usize {
219         let l = self.raw_size();
220         // align to 32-bit boundary
221         l + get_padding_size(l)
222     }
223 }
224 
225 impl Marshal for ExtendedReport {
226     /// marshal_to encodes the ExtendedReport in binary
227     fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
228         if buf.remaining_mut() < self.marshal_size() {
229             return Err(error::Error::BufferTooShort.into());
230         }
231 
232         let h = self.header();
233         let n = h.marshal_to(buf)?;
234         buf = &mut buf[n..];
235 
236         buf.put_u32(self.sender_ssrc);
237 
238         for report in &self.reports {
239             let n = report.marshal_to(buf)?;
240             buf = &mut buf[n..];
241         }
242 
243         if h.padding {
244             put_padding(buf, self.raw_size());
245         }
246 
247         Ok(self.marshal_size())
248     }
249 }
250 
251 impl Unmarshal for ExtendedReport {
252     /// Unmarshal decodes the ExtendedReport from binary
253     fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
254     where
255         Self: Sized,
256         B: Buf,
257     {
258         let raw_packet_len = raw_packet.remaining();
259         if raw_packet_len < (HEADER_LENGTH + SSRC_LENGTH) {
260             return Err(error::Error::PacketTooShort.into());
261         }
262 
263         let header = Header::unmarshal(raw_packet)?;
264         if header.packet_type != PacketType::ExtendedReport {
265             return Err(error::Error::WrongType.into());
266         }
267 
268         let sender_ssrc = raw_packet.get_u32();
269 
270         let mut offset = HEADER_LENGTH + SSRC_LENGTH;
271         let mut reports = vec![];
272         while raw_packet.remaining() > 0 {
273             if offset + XR_HEADER_LENGTH > raw_packet_len {
274                 return Err(error::Error::PacketTooShort.into());
275             }
276 
277             let block_type: BlockType = raw_packet.chunk()[0].into();
278             let report: Box<dyn Packet + Send + Sync> = match block_type {
279                 BlockType::LossRLE => Box::new(LossRLEReportBlock::unmarshal(raw_packet)?),
280                 BlockType::DuplicateRLE => {
281                     Box::new(DuplicateRLEReportBlock::unmarshal(raw_packet)?)
282                 }
283                 BlockType::PacketReceiptTimes => {
284                     Box::new(PacketReceiptTimesReportBlock::unmarshal(raw_packet)?)
285                 }
286                 BlockType::ReceiverReferenceTime => {
287                     Box::new(ReceiverReferenceTimeReportBlock::unmarshal(raw_packet)?)
288                 }
289                 BlockType::DLRR => Box::new(DLRRReportBlock::unmarshal(raw_packet)?),
290                 BlockType::StatisticsSummary => {
291                     Box::new(StatisticsSummaryReportBlock::unmarshal(raw_packet)?)
292                 }
293                 BlockType::VoIPMetrics => Box::new(VoIPMetricsReportBlock::unmarshal(raw_packet)?),
294                 _ => Box::new(UnknownReportBlock::unmarshal(raw_packet)?),
295             };
296 
297             offset += report.marshal_size();
298             reports.push(report);
299         }
300 
301         Ok(ExtendedReport {
302             sender_ssrc,
303             reports,
304         })
305     }
306 }
307