Skip to main content

rtc_rtcp/extended_report/
ssr.rs

1use super::*;
2
3const SSR_REPORT_BLOCK_LENGTH: u16 = 4 + 2 * 2 + 4 * 6 + 4;
4
5/// StatisticsSummaryReportBlock encodes a Statistics Summary Report
6/// Block as described in RFC 3611, section 4.6.
7///
8///  0                   1                   2                   3
9///  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
10/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
11/// |     BT=6      |L|D|J|ToH|rsvd.|       block length = 9        |
12/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13/// |                        ssrc of source                         |
14/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15/// |          begin_seq            |             end_seq           |
16/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17/// |                        lost_packets                           |
18/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19/// |                        dup_packets                            |
20/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
21/// |                         min_jitter                            |
22/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23/// |                         max_jitter                            |
24/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
25/// |                         mean_jitter                           |
26/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
27/// |                         dev_jitter                            |
28/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29/// | min_ttl_or_hl | max_ttl_or_hl |mean_ttl_or_hl | dev_ttl_or_hl |
30/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
31#[derive(Debug, Default, PartialEq, Eq, Clone)]
32pub struct StatisticsSummaryReportBlock {
33    //not included in marshal/unmarshal
34    /// Whether the loss fields are present.
35    pub loss_reports: bool,
36    /// Whether the duplicate fields are present.
37    pub duplicate_reports: bool,
38    /// Whether the jitter fields are present.
39    pub jitter_reports: bool,
40    /// Whether the TTL fields hold an IPv4 TTL, an IPv6 hop limit, or nothing.
41    pub ttl_or_hop_limit: TTLorHopLimitType,
42
43    //marshal/unmarshal
44    /// The SSRC being summarized.
45    pub ssrc: u32,
46    /// The first sequence number covered.
47    pub begin_seq: u16,
48    /// One past the last sequence number covered.
49    pub end_seq: u16,
50    /// Packets lost in the interval.
51    pub lost_packets: u32,
52    /// Duplicate packets in the interval.
53    pub dup_packets: u32,
54    /// Minimum observed jitter, in RTP timestamp units.
55    pub min_jitter: u32,
56    /// Maximum observed jitter.
57    pub max_jitter: u32,
58    /// Mean observed jitter.
59    pub mean_jitter: u32,
60    /// Standard deviation of observed jitter.
61    pub dev_jitter: u32,
62    /// Minimum TTL or hop limit seen.
63    pub min_ttl_or_hl: u8,
64    /// Maximum TTL or hop limit seen.
65    pub max_ttl_or_hl: u8,
66    /// Mean TTL or hop limit.
67    pub mean_ttl_or_hl: u8,
68    /// Standard deviation of TTL or hop limit.
69    pub dev_ttl_or_hl: u8,
70}
71
72impl fmt::Display for StatisticsSummaryReportBlock {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{self:?}")
75    }
76}
77
78/// TTLorHopLimitType encodes values for the ToH field in
79/// a StatisticsSummaryReportBlock
80#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
81pub enum TTLorHopLimitType {
82    #[default]
83    /// No TTL or hop-limit data is present.
84    Missing = 0,
85    /// The fields hold an IPv4 TTL.
86    IPv4 = 1,
87    /// The fields hold an IPv6 hop limit.
88    IPv6 = 2,
89}
90
91impl From<u8> for TTLorHopLimitType {
92    fn from(v: u8) -> Self {
93        match v {
94            1 => TTLorHopLimitType::IPv4,
95            2 => TTLorHopLimitType::IPv6,
96            _ => TTLorHopLimitType::Missing,
97        }
98    }
99}
100
101impl fmt::Display for TTLorHopLimitType {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        let s = match *self {
104            TTLorHopLimitType::Missing => "[ToH Missing]",
105            TTLorHopLimitType::IPv4 => "[ToH = IPv4]",
106            TTLorHopLimitType::IPv6 => "[ToH = IPv6]",
107        };
108        write!(f, "{s}")
109    }
110}
111
112impl StatisticsSummaryReportBlock {
113    /// The XR block header describing this block's type and length.
114    pub fn xr_header(&self) -> XRHeader {
115        let mut type_specific = 0x00;
116        if self.loss_reports {
117            type_specific |= 0x80;
118        }
119        if self.duplicate_reports {
120            type_specific |= 0x40;
121        }
122        if self.jitter_reports {
123            type_specific |= 0x20;
124        }
125        type_specific |= (self.ttl_or_hop_limit as u8 & 0x03) << 3;
126
127        XRHeader {
128            block_type: BlockType::StatisticsSummary,
129            type_specific,
130            block_length: (self.raw_size() / 4 - 1) as u16,
131        }
132    }
133}
134
135impl Packet for StatisticsSummaryReportBlock {
136    fn header(&self) -> Header {
137        Header::default()
138    }
139
140    /// destination_ssrc returns an array of ssrc values that this report block refers to.
141    fn destination_ssrc(&self) -> Vec<u32> {
142        vec![self.ssrc]
143    }
144
145    fn raw_size(&self) -> usize {
146        XR_HEADER_LENGTH + SSR_REPORT_BLOCK_LENGTH as usize
147    }
148
149    fn as_any(&self) -> &dyn Any {
150        self
151    }
152    fn equal(&self, other: &dyn Packet) -> bool {
153        other
154            .as_any()
155            .downcast_ref::<StatisticsSummaryReportBlock>()
156            == Some(self)
157    }
158    fn cloned(&self) -> Box<dyn Packet> {
159        Box::new(self.clone())
160    }
161}
162
163impl MarshalSize for StatisticsSummaryReportBlock {
164    fn marshal_size(&self) -> usize {
165        self.raw_size()
166    }
167}
168
169impl Marshal for StatisticsSummaryReportBlock {
170    /// marshal_to encodes the StatisticsSummaryReportBlock in binary
171    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
172        if buf.remaining_mut() < self.marshal_size() {
173            return Err(Error::BufferTooShort);
174        }
175
176        let h = self.xr_header();
177        let n = h.marshal_to(buf)?;
178        buf = &mut buf[n..];
179
180        buf.put_u32(self.ssrc);
181        buf.put_u16(self.begin_seq);
182        buf.put_u16(self.end_seq);
183        buf.put_u32(self.lost_packets);
184        buf.put_u32(self.dup_packets);
185        buf.put_u32(self.min_jitter);
186        buf.put_u32(self.max_jitter);
187        buf.put_u32(self.mean_jitter);
188        buf.put_u32(self.dev_jitter);
189        buf.put_u8(self.min_ttl_or_hl);
190        buf.put_u8(self.max_ttl_or_hl);
191        buf.put_u8(self.mean_ttl_or_hl);
192        buf.put_u8(self.dev_ttl_or_hl);
193
194        Ok(self.marshal_size())
195    }
196}
197
198impl Unmarshal for StatisticsSummaryReportBlock {
199    /// Unmarshal decodes the StatisticsSummaryReportBlock from binary
200    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
201    where
202        Self: Sized,
203        B: Buf,
204    {
205        if raw_packet.remaining() < XR_HEADER_LENGTH {
206            return Err(Error::PacketTooShort);
207        }
208
209        let xr_header = XRHeader::unmarshal(raw_packet)?;
210        let block_length = match xr_header.block_length.checked_mul(4) {
211            Some(length) => length,
212            None => return Err(Error::InvalidBlockSize),
213        };
214        if block_length != SSR_REPORT_BLOCK_LENGTH || raw_packet.remaining() < block_length as usize
215        {
216            return Err(Error::PacketTooShort);
217        }
218
219        let loss_reports = xr_header.type_specific & 0x80 != 0;
220        let duplicate_reports = xr_header.type_specific & 0x40 != 0;
221        let jitter_reports = xr_header.type_specific & 0x20 != 0;
222        let ttl_or_hop_limit: TTLorHopLimitType = ((xr_header.type_specific & 0x18) >> 3).into();
223
224        let ssrc = raw_packet.get_u32();
225        let begin_seq = raw_packet.get_u16();
226        let end_seq = raw_packet.get_u16();
227        let lost_packets = raw_packet.get_u32();
228        let dup_packets = raw_packet.get_u32();
229        let min_jitter = raw_packet.get_u32();
230        let max_jitter = raw_packet.get_u32();
231        let mean_jitter = raw_packet.get_u32();
232        let dev_jitter = raw_packet.get_u32();
233        let min_ttl_or_hl = raw_packet.get_u8();
234        let max_ttl_or_hl = raw_packet.get_u8();
235        let mean_ttl_or_hl = raw_packet.get_u8();
236        let dev_ttl_or_hl = raw_packet.get_u8();
237
238        Ok(StatisticsSummaryReportBlock {
239            loss_reports,
240            duplicate_reports,
241            jitter_reports,
242            ttl_or_hop_limit,
243
244            ssrc,
245            begin_seq,
246            end_seq,
247            lost_packets,
248            dup_packets,
249            min_jitter,
250            max_jitter,
251            mean_jitter,
252            dev_jitter,
253            min_ttl_or_hl,
254            max_ttl_or_hl,
255            mean_ttl_or_hl,
256            dev_ttl_or_hl,
257        })
258    }
259}