rtc_rtcp/transport_feedbacks/cc_feedback_report/
mod.rs1#[cfg(test)]
42mod cc_feedback_report_test;
43
44use crate::{header::*, packet::*, util::*};
45use shared::{
46 error::{Error, Result},
47 marshal::{Marshal, MarshalSize, Unmarshal},
48};
49
50use bytes::{Buf, BufMut};
51use std::any::Any;
52use std::fmt;
53
54const REPORT_BLOCK_OFFSET: usize = HEADER_LENGTH + SSRC_LENGTH;
56const REPORT_TIMESTAMP_LENGTH: usize = 4;
58const REPORT_BLOCK_HEADER_LENGTH: usize = 8;
60const METRIC_BLOCK_LENGTH: usize = 2;
62const MAX_METRIC_BLOCKS: usize = 16384;
64
65#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
72#[repr(u8)]
73pub enum Ecn {
74 #[default]
76 NotEct = 0,
77 Ect1 = 1,
79 Ect0 = 2,
81 Ce = 3,
83}
84
85impl Ecn {
86 fn from_bits(value: u8) -> Self {
90 match value & 0x03 {
91 0 => Ecn::NotEct,
92 1 => Ecn::Ect1,
93 2 => Ecn::Ect0,
94 _ => Ecn::Ce,
95 }
96 }
97}
98
99impl fmt::Display for Ecn {
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 let s = match self {
102 Ecn::NotEct => "Not-ECT (00)",
103 Ecn::Ect1 => "ECT(1) (01)",
104 Ecn::Ect0 => "ECT(0) (10)",
105 Ecn::Ce => "CE (11)",
106 };
107 write!(f, "{s}")
108 }
109}
110
111#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
116pub struct CcFeedbackMetricBlock {
117 pub received: bool,
122 pub ecn: Ecn,
124 pub arrival_time_offset: u16,
128}
129
130impl CcFeedbackMetricBlock {
131 fn marshal_word(&self) -> Result<u16> {
133 let received = u16::from(self.received);
134 let word = set_nbits_of_uint16(0, 1, 0, received)?;
135 let word = set_nbits_of_uint16(word, 2, 1, self.ecn as u16)?;
136 set_nbits_of_uint16(word, 13, 3, self.arrival_time_offset)
137 }
138
139 fn unmarshal_word(word: u16) -> Self {
145 let received = word & 0x8000 != 0;
146 if !received {
147 return Self::default();
148 }
149 Self {
150 received,
151 ecn: Ecn::from_bits((word >> 13) as u8),
152 arrival_time_offset: word & 0x1FFF,
153 }
154 }
155}
156
157impl fmt::Display for CcFeedbackMetricBlock {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 if self.received {
160 write!(f, "(rx, {}, {}/1024s)", self.ecn, self.arrival_time_offset)
161 } else {
162 write!(f, "(lost)")
163 }
164 }
165}
166
167#[derive(Debug, PartialEq, Eq, Default, Clone)]
169pub struct CcFeedbackReportBlock {
170 pub media_ssrc: u32,
172 pub begin_sequence: u16,
174 pub metric_blocks: Vec<CcFeedbackMetricBlock>,
176}
177
178impl CcFeedbackReportBlock {
179 fn raw_size(&self) -> usize {
185 REPORT_BLOCK_HEADER_LENGTH + METRIC_BLOCK_LENGTH * self.padded_metric_block_count()
186 }
187
188 fn padded_metric_block_count(&self) -> usize {
189 let count = self.metric_blocks.len();
190 if count.is_multiple_of(2) {
191 count
192 } else {
193 count + 1
194 }
195 }
196
197 fn marshal_to(&self, buf: &mut &mut [u8]) -> Result<()> {
198 if self.metric_blocks.len() > MAX_METRIC_BLOCKS {
199 return Err(Error::TooManyReports);
200 }
201
202 buf.put_u32(self.media_ssrc);
203 buf.put_u16(self.begin_sequence);
204 buf.put_u16(self.metric_blocks.len() as u16);
205
206 for block in &self.metric_blocks {
207 buf.put_u16(block.marshal_word()?);
208 }
209 for _ in self.metric_blocks.len()..self.padded_metric_block_count() {
211 buf.put_u16(0);
212 }
213
214 Ok(())
215 }
216
217 fn unmarshal_from<B: Buf>(raw_packet: &mut B, budget: usize) -> Result<(Self, usize)> {
222 if budget < REPORT_BLOCK_HEADER_LENGTH
223 || raw_packet.remaining() < REPORT_BLOCK_HEADER_LENGTH
224 {
225 return Err(Error::PacketTooShort);
226 }
227
228 let media_ssrc = raw_packet.get_u32();
229 let begin_sequence = raw_packet.get_u16();
230 let num_reports = raw_packet.get_u16() as usize;
231
232 let padded = if num_reports.is_multiple_of(2) {
233 num_reports
234 } else {
235 num_reports + 1
236 };
237 let consumed = REPORT_BLOCK_HEADER_LENGTH + METRIC_BLOCK_LENGTH * padded;
238 if budget < consumed || raw_packet.remaining() < METRIC_BLOCK_LENGTH * padded {
239 return Err(Error::PacketTooShort);
240 }
241
242 let mut metric_blocks = Vec::with_capacity(num_reports);
243 for _ in 0..num_reports {
244 metric_blocks.push(CcFeedbackMetricBlock::unmarshal_word(raw_packet.get_u16()));
245 }
246 if padded != num_reports {
247 raw_packet.advance(METRIC_BLOCK_LENGTH);
248 }
249
250 Ok((
251 Self {
252 media_ssrc,
253 begin_sequence,
254 metric_blocks,
255 },
256 consumed,
257 ))
258 }
259}
260
261impl fmt::Display for CcFeedbackReportBlock {
262 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
263 write!(
264 f,
265 "\tssrc={:x} begin_seq={} reports={}\n\t\t",
266 self.media_ssrc,
267 self.begin_sequence,
268 self.metric_blocks.len()
269 )?;
270 for block in &self.metric_blocks {
271 write!(f, "{block} ")?;
272 }
273 writeln!(f)
274 }
275}
276
277#[derive(Debug, PartialEq, Eq, Default, Clone)]
281pub struct CcFeedbackReport {
282 pub sender_ssrc: u32,
284 pub report_blocks: Vec<CcFeedbackReportBlock>,
286 pub report_timestamp: u32,
289}
290
291impl fmt::Display for CcFeedbackReport {
292 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
293 writeln!(
294 f,
295 "CcFeedbackReport sender_ssrc={:x} report_timestamp={}",
296 self.sender_ssrc, self.report_timestamp
297 )?;
298 for block in &self.report_blocks {
299 write!(f, "{block}")?;
300 }
301 Ok(())
302 }
303}
304
305impl Packet for CcFeedbackReport {
306 fn header(&self) -> Header {
307 Header {
308 padding: get_padding_size(self.raw_size()) != 0,
309 count: FORMAT_CCFB,
310 packet_type: PacketType::TransportSpecificFeedback,
311 length: ((self.marshal_size() / 4) - 1) as u16,
312 }
313 }
314
315 fn destination_ssrc(&self) -> Vec<u32> {
320 self.report_blocks
321 .iter()
322 .map(|block| block.media_ssrc)
323 .collect()
324 }
325
326 fn raw_size(&self) -> usize {
327 let blocks: usize = self.report_blocks.iter().map(|b| b.raw_size()).sum();
328 REPORT_BLOCK_OFFSET + blocks + REPORT_TIMESTAMP_LENGTH
329 }
330
331 fn as_any(&self) -> &dyn Any {
332 self
333 }
334
335 fn equal(&self, other: &dyn Packet) -> bool {
336 other.as_any().downcast_ref::<CcFeedbackReport>() == Some(self)
337 }
338
339 fn cloned(&self) -> Box<dyn Packet> {
340 Box::new(self.clone())
341 }
342}
343
344impl MarshalSize for CcFeedbackReport {
345 fn marshal_size(&self) -> usize {
346 let l = self.raw_size();
347 l + get_padding_size(l)
349 }
350}
351
352impl Marshal for CcFeedbackReport {
353 fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
354 if buf.remaining_mut() < self.marshal_size() {
355 return Err(Error::BufferTooShort);
356 }
357
358 let h = self.header();
359 let n = h.marshal_to(buf)?;
360 buf = &mut buf[n..];
361
362 buf.put_u32(self.sender_ssrc);
363 for block in &self.report_blocks {
364 block.marshal_to(&mut buf)?;
365 }
366 buf.put_u32(self.report_timestamp);
367
368 if h.padding {
369 put_padding(buf, self.raw_size());
370 }
371
372 Ok(self.marshal_size())
373 }
374}
375
376impl Unmarshal for CcFeedbackReport {
377 fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
378 where
379 Self: Sized,
380 B: Buf,
381 {
382 let raw_packet_len = raw_packet.remaining();
383 if raw_packet_len < REPORT_BLOCK_OFFSET + REPORT_TIMESTAMP_LENGTH {
384 return Err(Error::PacketTooShort);
385 }
386
387 let h = Header::unmarshal(raw_packet)?;
388 if h.packet_type != PacketType::TransportSpecificFeedback || h.count != FORMAT_CCFB {
389 return Err(Error::WrongType);
390 }
391
392 let packet_len = 4 * (h.length as usize + 1);
395 if raw_packet_len < packet_len || packet_len < REPORT_BLOCK_OFFSET + REPORT_TIMESTAMP_LENGTH
396 {
397 return Err(Error::PacketTooShort);
398 }
399
400 let sender_ssrc = raw_packet.get_u32();
401
402 let mut remaining_blocks_len = packet_len - REPORT_BLOCK_OFFSET - REPORT_TIMESTAMP_LENGTH;
403 let mut report_blocks = Vec::new();
404 while remaining_blocks_len > 0 {
405 let (block, consumed) =
406 CcFeedbackReportBlock::unmarshal_from(raw_packet, remaining_blocks_len)?;
407 report_blocks.push(block);
408 remaining_blocks_len -= consumed;
409 }
410
411 let report_timestamp = raw_packet.get_u32();
412
413 Ok(CcFeedbackReport {
414 sender_ssrc,
415 report_blocks,
416 report_timestamp,
417 })
418 }
419}