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