Skip to main content

rtc_rtcp/extended_report/
dlrr.rs

1use super::*;
2
3const DLRR_REPORT_LENGTH: u16 = 12;
4
5/// DLRRReport encodes a single report inside a DLRRReportBlock.
6#[derive(Debug, Default, PartialEq, Eq, Clone)]
7pub struct DLRRReport {
8    pub ssrc: u32,
9    pub last_rr: u32,
10    pub dlrr: u32,
11}
12
13impl fmt::Display for DLRRReport {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        write!(f, "{self:?}")
16    }
17}
18
19/// DLRRReportBlock encodes a DLRR Report Block as described in
20/// RFC 3611 section 4.5.
21///
22///  0                   1                   2                   3
23///  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
24/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25/// |     BT=5      |   reserved    |         block length          |
26/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
27/// |                 SSRC_1 (ssrc of first receiver)               | sub-
28/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
29/// |                         last RR (LRR)                         |   1
30/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31/// |                   delay since last RR (DLRR)                  |
32/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
33/// |                 SSRC_2 (ssrc of second receiver)              | sub-
34/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
35/// :                               ...                             :   2
36/// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
37#[derive(Debug, Default, PartialEq, Eq, Clone)]
38pub struct DLRRReportBlock {
39    pub reports: Vec<DLRRReport>,
40}
41
42impl fmt::Display for DLRRReportBlock {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        write!(f, "{self:?}")
45    }
46}
47
48impl DLRRReportBlock {
49    pub fn xr_header(&self) -> XRHeader {
50        XRHeader {
51            block_type: BlockType::DLRR,
52            type_specific: 0,
53            block_length: (self.raw_size() / 4 - 1) as u16,
54        }
55    }
56}
57
58impl Packet for DLRRReportBlock {
59    fn header(&self) -> Header {
60        Header::default()
61    }
62
63    /// destination_ssrc returns an array of ssrc values that this report block refers to.
64    fn destination_ssrc(&self) -> Vec<u32> {
65        let mut ssrc = Vec::with_capacity(self.reports.len());
66        for r in &self.reports {
67            ssrc.push(r.ssrc);
68        }
69        ssrc
70    }
71
72    fn raw_size(&self) -> usize {
73        XR_HEADER_LENGTH + self.reports.len() * 4 * 3
74    }
75
76    fn as_any(&self) -> &dyn Any {
77        self
78    }
79    fn equal(&self, other: &dyn Packet) -> bool {
80        other.as_any().downcast_ref::<DLRRReportBlock>() == Some(self)
81    }
82    fn cloned(&self) -> Box<dyn Packet> {
83        Box::new(self.clone())
84    }
85}
86
87impl MarshalSize for DLRRReportBlock {
88    fn marshal_size(&self) -> usize {
89        self.raw_size()
90    }
91}
92
93impl Marshal for DLRRReportBlock {
94    /// marshal_to encodes the DLRRReportBlock in binary
95    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
96        if buf.remaining_mut() < self.marshal_size() {
97            return Err(Error::BufferTooShort);
98        }
99
100        let h = self.xr_header();
101        let n = h.marshal_to(buf)?;
102        buf = &mut buf[n..];
103
104        for rep in &self.reports {
105            buf.put_u32(rep.ssrc);
106            buf.put_u32(rep.last_rr);
107            buf.put_u32(rep.dlrr);
108        }
109
110        Ok(self.marshal_size())
111    }
112}
113
114impl Unmarshal for DLRRReportBlock {
115    /// Unmarshal decodes the DLRRReportBlock from binary
116    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
117    where
118        Self: Sized,
119        B: Buf,
120    {
121        if raw_packet.remaining() < XR_HEADER_LENGTH {
122            return Err(Error::PacketTooShort);
123        }
124
125        let xr_header = XRHeader::unmarshal(raw_packet)?;
126        let block_length = match xr_header.block_length.checked_mul(4) {
127            Some(length) => length,
128            None => return Err(Error::InvalidBlockSize),
129        };
130        if block_length % DLRR_REPORT_LENGTH != 0 || raw_packet.remaining() < block_length as usize
131        {
132            return Err(Error::PacketTooShort);
133        }
134
135        let mut offset = 0;
136        let mut reports = vec![];
137        while offset < block_length {
138            let ssrc = raw_packet.get_u32();
139            let last_rr = raw_packet.get_u32();
140            let dlrr = raw_packet.get_u32();
141            reports.push(DLRRReport {
142                ssrc,
143                last_rr,
144                dlrr,
145            });
146            offset += DLRR_REPORT_LENGTH;
147        }
148
149        Ok(DLRRReportBlock { reports })
150    }
151}