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