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