Skip to main content

rtc_rtcp/extended_report/
mod.rs

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